Transaction Hash:
Block:
10339320 at Jun-26-2020 04:40:45 AM +UTC
Transaction Fee:
0.004635802 ETH
$11.44
Gas Used:
149,542 Gas / 31 Gwei
Emitted Events:
74 |
FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000009e0a387283ad0534d983997fc52720250ffcaad1, 0x0000000000000000000000006c60c2a9abb2ca13d5a65fd5aecd362007458d40, 000000000000000000000000000000000000000000000000000000038ff37900 )
|
75 |
oToken.ERC20CollateralAdded( vaultOwner=[Sender] 0x9e0a387283ad0534d983997fc52720250ffcaad1, amount=15300000000, payer=[Sender] 0x9e0a387283ad0534d983997fc52720250ffcaad1 )
|
76 |
oToken.Transfer( from=0x0000000000000000000000000000000000000000, to=[Receiver] oToken, value=695454546 )
|
77 |
oToken.IssuedOTokens( issuedTo=[Receiver] oToken, oTokensIssued=695454546, vaultOwner=[Sender] 0x9e0a387283ad0534d983997fc52720250ffcaad1 )
|
78 |
oToken.Approval( owner=[Receiver] oToken, spender=OptionsExchange, value=695454546 )
|
79 |
oToken.Transfer( from=[Receiver] oToken, to=OptionsExchange, value=695454546 )
|
80 |
oToken.Approval( owner=[Receiver] oToken, spender=OptionsExchange, value=0 )
|
81 |
oToken.Approval( owner=OptionsExchange, spender=Vyper_contract, value=695454546 )
|
82 |
oToken.Transfer( from=OptionsExchange, to=Vyper_contract, value=695454546 )
|
83 |
oToken.Approval( owner=OptionsExchange, spender=Vyper_contract, value=0 )
|
84 |
Vyper_contract.EthPurchase( buyer=OptionsExchange, tokens_sold=695454546, eth_bought=46439061067894016 )
|
85 |
OptionsExchange.SellOTokens( seller=[Receiver] oToken, receiver=[Sender] 0x9e0a387283ad0534d983997fc52720250ffcaad1, oTokenAddress=[Receiver] oToken, payoutTokenAddress=0x0000000000000000000000000000000000000000, oTokensToSell=695454546, payoutTokensReceived=46439061067894016 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x35F61DFB...D5B3a738d
Miner
| (firepool) | 31.061883968797957632 Eth | 31.066519770797957632 Eth | 0.004635802 | |
0x643807F6...0B02F146b | 0.668376789558785004 Eth | 0.621937728490890988 Eth | 0.046439061067894016 | ||
0x6c60c2A9...007458d40 | |||||
0x9E0a3872...50FFCaad1 |
0.237939901729239201 Eth
Nonce: 18
|
0.279743160797133217 Eth
Nonce: 19
| 0.041803259067894016 | ||
0xA0b86991...E3606eB48 |
Execution Trace
oToken.addAndSellERC20CollateralOption( amtToCreate=695454546, amtCollateral=15300000000, receiver=0x9E0a387283Ad0534d983997fC52720250FFCaad1 )

FiatTokenProxy.23b872dd( )
-
FiatTokenV1.transferFrom( _from=0x9E0a387283Ad0534d983997fC52720250FFCaad1, _to=0x6c60c2A9ABB2cA13d5A65Fd5AEcD362007458d40, _value=15300000000 ) => ( True )
-
-
oToken.approve( spender=0x39246c4F3F6592C974EBC44F80bA6dC69b817c71, amount=695454546 ) => ( True )
OptionsExchange.sellOTokens( receiver=0x9E0a387283Ad0534d983997fC52720250FFCaad1, oTokenAddress=0x6c60c2A9ABB2cA13d5A65Fd5AEcD362007458d40, payoutTokenAddress=0x0000000000000000000000000000000000000000, oTokensToSell=695454546 )
-
oToken.transferFrom( sender=0x6c60c2A9ABB2cA13d5A65Fd5AEcD362007458d40, recipient=0x39246c4F3F6592C974EBC44F80bA6dC69b817c71, amount=695454546 ) => ( True )
-
Vyper_contract.getExchange( token=0x6c60c2A9ABB2cA13d5A65Fd5AEcD362007458d40 ) => ( out=0x643807F6142f8A6717BE600A34B7d610B02F146b )
-
oToken.approve( spender=0x643807F6142f8A6717BE600A34B7d610B02F146b, amount=695454546 ) => ( True )
Vyper_contract.tokenToEthTransferInput( tokens_sold=695454546, min_eth=1, deadline=1651753129000, recipient=0x9E0a387283Ad0534d983997fC52720250FFCaad1 ) => ( out=46439061067894016 )
Vyper_contract.tokenToEthTransferInput( tokens_sold=695454546, min_eth=1, deadline=1651753129000, recipient=0x9E0a387283Ad0534d983997fC52720250FFCaad1 ) => ( out=46439061067894016 )
-
oToken.balanceOf( account=0x643807F6142f8A6717BE600A34B7d610B02F146b ) => ( 9285972249 )
- ETH 0.046439061067894016
0x9e0a387283ad0534d983997fc52720250ffcaad1.CALL( )
-
oToken.transferFrom( sender=0x39246c4F3F6592C974EBC44F80bA6dC69b817c71, recipient=0x643807F6142f8A6717BE600A34B7d610B02F146b, amount=695454546 ) => ( True )
-
-
addAndSellERC20CollateralOption[oToken (ln:2290)]
addERC20Collateral[oToken (ln:2295)]
issueOTokens[oToken (ln:2296)]
approve[oToken (ln:2297)]
sellOTokens[oToken (ln:2298)]
File 1 of 7: oToken
File 2 of 7: FiatTokenProxy
File 3 of 7: OptionsExchange
File 4 of 7: Vyper_contract
File 5 of 7: FiatTokenV1
File 6 of 7: Vyper_contract
File 7 of 7: Vyper_contract
// File: @openzeppelin/contracts/GSN/Context.sol pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts/math/SafeMath.sol 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) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); 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-contracts/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) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); 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) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: @openzeppelin/contracts/token/ERC20/ERC20.sol pragma solidity ^0.5.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { 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); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } } // File: contracts/lib/CompoundOracleInterface.sol pragma solidity ^0.5.0; // AT MAINNET ADDRESS: 0x02557a5E05DeFeFFD4cAe6D83eA3d173B272c904 contract CompoundOracleInterface { // returns asset:eth -- to get USDC:eth, have to do 10**24/result, constructor() public { } /** * @notice retrieves price of an asset * @dev function to get price for an asset * @param asset Asset for which to get the price * @return uint mantissa of asset price (scaled by 1e18) or zero if unset or contract paused */ function getPrice(address asset) public view returns (uint); function getUnderlyingPrice(ERC20 cToken) public view returns (uint); // function getPrice(address asset) public view returns (uint) { // return 527557000000000; // } } // File: contracts/lib/UniswapExchangeInterface.sol pragma solidity 0.5.10; // Solidity Interface contract UniswapExchangeInterface { // Address of ERC20 token sold on this exchange function tokenAddress() external view returns (address token); // Address of Uniswap Factory function factoryAddress() external view returns (address factory); // Provide Liquidity function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256); function removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline) external returns (uint256, uint256); // Get Prices function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought); function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold); function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought); function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold); // Trade ETH to ERC20 function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256 tokens_bought); function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256 tokens_bought); function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256 eth_sold); function ethToTokenTransferOutput(uint256 tokens_bought, uint256 deadline, address recipient) external payable returns (uint256 eth_sold); // Trade ERC20 to ETH function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256 eth_bought); function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline, address recipient) external returns (uint256 eth_bought); function tokenToEthSwapOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline) external returns (uint256 tokens_sold); function tokenToEthTransferOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline, address recipient) external returns (uint256 tokens_sold); // Trade ERC20 to ERC20 function tokenToTokenSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address token_addr) external returns (uint256 tokens_bought); function tokenToTokenTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_bought); function tokenToTokenSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address token_addr) external returns (uint256 tokens_sold); function tokenToTokenTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_sold); // Trade ERC20 to Custom Pool function tokenToExchangeSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address exchange_addr) external returns (uint256 tokens_bought); function tokenToExchangeTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_bought); function tokenToExchangeSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address exchange_addr) external returns (uint256 tokens_sold); function tokenToExchangeTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_sold); // ERC20 comaptibility for liquidity tokens bytes32 public name; bytes32 public symbol; uint256 public decimals; function transfer(address _to, uint256 _value) external returns (bool); function transferFrom(address _from, address _to, uint256 value) external returns (bool); function approve(address _spender, uint256 _value) external returns (bool); function allowance(address _owner, address _spender) external view returns (uint256); function balanceOf(address _owner) external view returns (uint256); function totalSupply() external view returns (uint256); // Never use function setup(address token_addr) external; } // File: contracts/lib/UniswapFactoryInterface.sol pragma solidity 0.5.10; // Solidity Interface contract UniswapFactoryInterface { // Public Variables address public exchangeTemplate; uint256 public tokenCount; // // Create Exchange function createExchange(address token) external returns (address exchange); // Get Exchange and Token Info function getExchange(address token) external view returns (address exchange); function getToken(address exchange) external view returns (address token); function getTokenWithId(uint256 tokenId) external view returns (address token); // Never use function initializeFactory(address template) external; // function createExchange(address token) external returns (address exchange) { // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } // // Get Exchange and Token Info // function getExchange(address token) external view returns (address exchange){ // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } // function getToken(address exchange) external view returns (address token) { // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } // function getTokenWithId(uint256 tokenId) external view returns (address token) { // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } } // File: contracts/OptionsUtils.sol pragma solidity 0.5.10; contract OptionsUtils { // defauls are for mainnet UniswapFactoryInterface public UNISWAP_FACTORY; CompoundOracleInterface public COMPOUND_ORACLE; constructor(address _uniswapFactory, address _compoundOracle) public { UNISWAP_FACTORY = UniswapFactoryInterface(_uniswapFactory); COMPOUND_ORACLE = CompoundOracleInterface(_compoundOracle); } // TODO: for now gets Uniswap, later update to get other exchanges function getExchange(address _token) public view returns (UniswapExchangeInterface) { if (address(UNISWAP_FACTORY.getExchange(_token)) == address(0)) { revert("No payout exchange"); } UniswapExchangeInterface exchange = UniswapExchangeInterface( UNISWAP_FACTORY.getExchange(_token) ); return exchange; } function isETH(IERC20 _ierc20) public pure returns (bool) { return _ierc20 == IERC20(0); } } // File: contracts/OptionsExchange.sol pragma solidity 0.5.10; contract OptionsExchange { uint256 constant LARGE_BLOCK_SIZE = 1651753129000; uint256 constant LARGE_APPROVAL_NUMBER = 10**30; UniswapFactoryInterface public UNISWAP_FACTORY; constructor(address _uniswapFactory) public { UNISWAP_FACTORY = UniswapFactoryInterface(_uniswapFactory); } /*** Events ***/ event SellOTokens( address seller, address payable receiver, address oTokenAddress, address payoutTokenAddress, uint256 oTokensToSell, uint256 payoutTokensReceived ); event BuyOTokens( address buyer, address payable receiver, address oTokenAddress, address paymentTokenAddress, uint256 oTokensToBuy, uint256 premiumPaid ); /** * @notice This function sells oTokens on Uniswap and sends back payoutTokens to the receiver * @param receiver The address to send the payout tokens back to * @param oTokenAddress The address of the oToken to sell * @param payoutTokenAddress The address of the token to receive the premiums in * @param oTokensToSell The number of oTokens to sell */ function sellOTokens( address payable receiver, address oTokenAddress, address payoutTokenAddress, uint256 oTokensToSell ) public { // @note: first need to bootstrap the uniswap exchange to get the address. IERC20 oToken = IERC20(oTokenAddress); IERC20 payoutToken = IERC20(payoutTokenAddress); oToken.transferFrom(msg.sender, address(this), oTokensToSell); uint256 payoutTokensReceived = uniswapSellOToken( oToken, payoutToken, oTokensToSell, receiver ); emit SellOTokens( msg.sender, receiver, oTokenAddress, payoutTokenAddress, oTokensToSell, payoutTokensReceived ); } /** * @notice This function buys oTokens on Uniswap and using paymentTokens from the receiver * @param receiver The address to send the oTokens back to * @param oTokenAddress The address of the oToken to buy * @param paymentTokenAddress The address of the token to pay the premiums in * @param oTokensToBuy The number of oTokens to buy */ function buyOTokens( address payable receiver, address oTokenAddress, address paymentTokenAddress, uint256 oTokensToBuy ) public payable { IERC20 oToken = IERC20(oTokenAddress); IERC20 paymentToken = IERC20(paymentTokenAddress); uniswapBuyOToken(paymentToken, oToken, oTokensToBuy, receiver); } /** * @notice This function calculates the amount of premiums that the seller * will receive if they sold oTokens on Uniswap * @param oTokenAddress The address of the oToken to sell * @param payoutTokenAddress The address of the token to receive the premiums in * @param oTokensToSell The number of oTokens to sell */ function premiumReceived( address oTokenAddress, address payoutTokenAddress, uint256 oTokensToSell ) public view returns (uint256) { // get the amount of ETH that will be paid out if oTokensToSell is sold. UniswapExchangeInterface oTokenExchange = getExchange(oTokenAddress); uint256 ethReceived = oTokenExchange.getTokenToEthInputPrice( oTokensToSell ); if (!isETH(IERC20(payoutTokenAddress))) { // get the amount of payout tokens that will be received if the ethRecieved is sold. UniswapExchangeInterface payoutExchange = getExchange( payoutTokenAddress ); return payoutExchange.getEthToTokenInputPrice(ethReceived); } return ethReceived; } /** * @notice This function calculates the premiums to be paid if a buyer wants to * buy oTokens on Uniswap * @param oTokenAddress The address of the oToken to buy * @param paymentTokenAddress The address of the token to pay the premiums in * @param oTokensToBuy The number of oTokens to buy */ function premiumToPay( address oTokenAddress, address paymentTokenAddress, uint256 oTokensToBuy ) public view returns (uint256) { // get the amount of ETH that needs to be paid for oTokensToBuy. UniswapExchangeInterface oTokenExchange = getExchange(oTokenAddress); uint256 ethToPay = oTokenExchange.getEthToTokenOutputPrice( oTokensToBuy ); if (!isETH(IERC20(paymentTokenAddress))) { // get the amount of paymentTokens that needs to be paid to get the desired ethToPay. UniswapExchangeInterface paymentTokenExchange = getExchange( paymentTokenAddress ); return paymentTokenExchange.getTokenToEthOutputPrice(ethToPay); } return ethToPay; } function uniswapSellOToken( IERC20 oToken, IERC20 payoutToken, uint256 _amt, address payable _transferTo ) internal returns (uint256) { require(!isETH(oToken), "Can only sell oTokens"); UniswapExchangeInterface exchange = getExchange(address(oToken)); if (isETH(payoutToken)) { //Token to ETH oToken.approve(address(exchange), _amt); return exchange.tokenToEthTransferInput( _amt, 1, LARGE_BLOCK_SIZE, _transferTo ); } else { //Token to Token oToken.approve(address(exchange), _amt); return exchange.tokenToTokenTransferInput( _amt, 1, 1, LARGE_BLOCK_SIZE, _transferTo, address(payoutToken) ); } } function uniswapBuyOToken( IERC20 paymentToken, IERC20 oToken, uint256 _amt, address payable _transferTo ) public returns (uint256) { require(!isETH(oToken), "Can only buy oTokens"); if (!isETH(paymentToken)) { UniswapExchangeInterface exchange = getExchange( address(paymentToken) ); uint256 paymentTokensToTransfer = premiumToPay( address(oToken), address(paymentToken), _amt ); paymentToken.transferFrom( msg.sender, address(this), paymentTokensToTransfer ); // Token to Token paymentToken.approve(address(exchange), LARGE_APPROVAL_NUMBER); emit BuyOTokens( msg.sender, _transferTo, address(oToken), address(paymentToken), _amt, paymentTokensToTransfer ); return exchange.tokenToTokenTransferInput( paymentTokensToTransfer, 1, 1, LARGE_BLOCK_SIZE, _transferTo, address(oToken) ); } else { // ETH to Token UniswapExchangeInterface exchange = UniswapExchangeInterface( UNISWAP_FACTORY.getExchange(address(oToken)) ); uint256 ethToTransfer = exchange.getEthToTokenOutputPrice(_amt); emit BuyOTokens( msg.sender, _transferTo, address(oToken), address(paymentToken), _amt, ethToTransfer ); return exchange.ethToTokenTransferOutput.value(ethToTransfer)( _amt, LARGE_BLOCK_SIZE, _transferTo ); } } function getExchange(address _token) internal view returns (UniswapExchangeInterface) { UniswapExchangeInterface exchange = UniswapExchangeInterface( UNISWAP_FACTORY.getExchange(_token) ); if (address(exchange) == address(0)) { revert("No payout exchange"); } return exchange; } function isETH(IERC20 _ierc20) internal pure returns (bool) { return _ierc20 == IERC20(0); } function() external payable { // to get ether from uniswap exchanges } } // File: @openzeppelin/contracts/token/ERC20/ERC20Detailed.sol pragma solidity ^0.5.0; /** * @dev Optional functions from the ERC20 standard. */ contract ERC20Detailed is IERC20 { string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol, uint8 decimals) public { _name = name; _symbol = symbol; _decimals = decimals; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } } // File: @openzeppelin/contracts/ownership/Ownable.sol pragma solidity ^0.5.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { _owner = _msgSender(); emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: contracts/OptionsContract.sol pragma solidity 0.5.10; /** * @title Opyn's Options Contract * @author Opyn */ contract OptionsContract is Ownable, ERC20 { using SafeMath for uint256; /* represents floting point numbers, where number = value * 10 ** exponent i.e 0.1 = 10 * 10 ** -3 */ struct Number { uint256 value; int32 exponent; } // Keeps track of the weighted collateral and weighted debt for each vault. struct Vault { uint256 collateral; uint256 oTokensIssued; uint256 underlying; bool owned; } OptionsExchange public optionsExchange; mapping(address => Vault) internal vaults; address payable[] internal vaultOwners; // 10 is 0.01 i.e. 1% incentive. Number public liquidationIncentive = Number(10, -3); // 100 is egs. 0.1 i.e. 10%. Number public transactionFee = Number(0, -3); /* 500 is 0.5. Max amount that a Vault can be liquidated by i.e. max collateral that can be taken in one function call */ Number public liquidationFactor = Number(500, -3); /* 16 means 1.6. The minimum ratio of a Vault's collateral to insurance promised. The ratio is calculated as below: vault.collateral / (Vault.oTokensIssued * strikePrice) */ Number public minCollateralizationRatio = Number(16, -1); // The amount of insurance promised per oToken Number public strikePrice; // The amount of underlying that 1 oToken protects. Number public oTokenExchangeRate; /* UNIX time. Exercise period starts at `(expiry - windowSize)` and ends at `expiry` */ uint256 internal windowSize; /* The total fees accumulated in the contract any time liquidate or exercise is called */ uint256 internal totalFee; // The time of expiry of the options contract uint256 public expiry; // The precision of the collateral int32 public collateralExp = -18; // The precision of the underlying int32 public underlyingExp = -18; // The collateral asset IERC20 public collateral; // The asset being protected by the insurance IERC20 public underlying; // The asset in which insurance is denominated in. IERC20 public strike; // The Oracle used for the contract CompoundOracleInterface public COMPOUND_ORACLE; // The name of the contract string public name; // The symbol of the contract string public symbol; // The number of decimals of the contract uint8 public decimals; /** * @param _collateral The collateral asset * @param _collExp The precision of the collateral (-18 if ETH) * @param _underlying The asset that is being protected * @param _underlyingExp The precision of the underlying asset * @param _oTokenExchangeExp The precision of the `amount of underlying` that 1 oToken protects * @param _strikePrice The amount of strike asset that will be paid out per oToken * @param _strikeExp The precision of the strike price. * @param _strike The asset in which the insurance is calculated * @param _expiry The time at which the insurance expires * @param _optionsExchange The contract which interfaces with the exchange + oracle * @param _oracleAddress The address of the oracle * @param _windowSize UNIX time. Exercise window is from `expiry - _windowSize` to `expiry`. */ constructor( IERC20 _collateral, int32 _collExp, IERC20 _underlying, int32 _underlyingExp, int32 _oTokenExchangeExp, uint256 _strikePrice, int32 _strikeExp, IERC20 _strike, uint256 _expiry, OptionsExchange _optionsExchange, address _oracleAddress, uint256 _windowSize ) public { require(block.timestamp < _expiry, "Can't deploy an expired contract"); require( _windowSize <= _expiry, "Exercise window can't be longer than the contract's lifespan" ); require( isWithinExponentRange(_collExp), "collateral exponent not within expected range" ); require( isWithinExponentRange(_underlyingExp), "underlying exponent not within expected range" ); require( isWithinExponentRange(_strikeExp), "strike price exponent not within expected range" ); require( isWithinExponentRange(_oTokenExchangeExp), "oToken exchange rate exponent not within expected range" ); collateral = _collateral; collateralExp = _collExp; underlying = _underlying; underlyingExp = _underlyingExp; oTokenExchangeRate = Number(1, _oTokenExchangeExp); strikePrice = Number(_strikePrice, _strikeExp); strike = _strike; expiry = _expiry; COMPOUND_ORACLE = CompoundOracleInterface(_oracleAddress); optionsExchange = _optionsExchange; windowSize = _windowSize; } /*** Events ***/ event VaultOpened(address payable vaultOwner); event ETHCollateralAdded( address payable vaultOwner, uint256 amount, address payer ); event ERC20CollateralAdded( address payable vaultOwner, uint256 amount, address payer ); event IssuedOTokens( address issuedTo, uint256 oTokensIssued, address payable vaultOwner ); event Liquidate( uint256 amtCollateralToPay, address payable vaultOwner, address payable liquidator ); event Exercise( uint256 amtUnderlyingToPay, uint256 amtCollateralToPay, address payable exerciser, address payable vaultExercisedFrom ); event RedeemVaultBalance( uint256 amtCollateralRedeemed, uint256 amtUnderlyingRedeemed, address payable vaultOwner ); event BurnOTokens(address payable vaultOwner, uint256 oTokensBurned); event RemoveCollateral(uint256 amtRemoved, address payable vaultOwner); event UpdateParameters( uint256 liquidationIncentive, uint256 liquidationFactor, uint256 transactionFee, uint256 minCollateralizationRatio, address owner ); event TransferFee(address payable to, uint256 fees); event RemoveUnderlying( uint256 amountUnderlying, address payable vaultOwner ); /** * @dev Throws if called Options contract is expired. */ modifier notExpired() { require(!hasExpired(), "Options contract expired"); _; } /** * @notice This function gets the array of vaultOwners */ function getVaultOwners() public view returns (address payable[] memory) { address payable[] memory owners; uint256 index = 0; for (uint256 i = 0; i < vaultOwners.length; i++) { if (hasVault(vaultOwners[i])) { owners[index] = vaultOwners[i]; index++; } } return owners; } /** * @notice Can only be called by owner. Used to update the fees, minminCollateralizationRatio, etc * @param _liquidationIncentive The incentive paid to liquidator. 10 is 0.01 i.e. 1% incentive. * @param _liquidationFactor Max amount that a Vault can be liquidated by. 500 is 0.5. * @param _transactionFee The fees paid to our protocol every time a execution happens. 100 is egs. 0.1 i.e. 10%. * @param _minCollateralizationRatio The minimum ratio of a Vault's collateral to insurance promised. 16 means 1.6. */ function updateParameters( uint256 _liquidationIncentive, uint256 _liquidationFactor, uint256 _transactionFee, uint256 _minCollateralizationRatio ) public onlyOwner { require( _liquidationIncentive <= 200, "Can't have >20% liquidation incentive" ); require( _liquidationFactor <= 1000, "Can't liquidate more than 100% of the vault" ); require(_transactionFee <= 100, "Can't have transaction fee > 10%"); require( _minCollateralizationRatio >= 10, "Can't have minCollateralizationRatio < 1" ); liquidationIncentive.value = _liquidationIncentive; liquidationFactor.value = _liquidationFactor; transactionFee.value = _transactionFee; minCollateralizationRatio.value = _minCollateralizationRatio; emit UpdateParameters( _liquidationIncentive, _liquidationFactor, _transactionFee, _minCollateralizationRatio, owner() ); } /** * @notice Can only be called by owner. Used to set the name, symbol and decimals of the contract * @param _name The name of the contract * @param _symbol The symbol of the contract */ function setDetails(string memory _name, string memory _symbol) public onlyOwner { name = _name; symbol = _symbol; decimals = uint8(-1 * oTokenExchangeRate.exponent); require( decimals >= 0, "1 oToken cannot protect less than the smallest unit of the asset" ); } /** * @notice Can only be called by owner. Used to take out the protocol fees from the contract. * @param _address The address to send the fee to. */ function transferFee(address payable _address) public onlyOwner { uint256 fees = totalFee; totalFee = 0; transferCollateral(_address, fees); emit TransferFee(_address, fees); } /** * @notice Checks if a `owner` has already created a Vault * @param owner The address of the supposed owner * @return true or false */ function hasVault(address payable owner) public view returns (bool) { return vaults[owner].owned; } /** * @notice Creates a new empty Vault and sets the owner of the vault to be the msg.sender. */ function openVault() public notExpired returns (bool) { require(!hasVault(msg.sender), "Vault already created"); vaults[msg.sender] = Vault(0, 0, 0, true); vaultOwners.push(msg.sender); emit VaultOpened(msg.sender); return true; } /** * @notice If the collateral type is ETH, anyone can call this function any time before * expiry to increase the amount of collateral in a Vault. Will fail if ETH is not the * collateral asset. * Remember that adding ETH collateral even if no oTokens have been created can put the owner at a * risk of losing the collateral if an exercise event happens. * Ensure that you issue and immediately sell oTokens to allow the owner to earn premiums. * (Either call the createAndSell function in the oToken contract or batch the * addERC20Collateral, issueOTokens and sell transactions and ensure they happen atomically to protect * the end user). * @param vaultOwner the index of the Vault to which collateral will be added. */ function addETHCollateral(address payable vaultOwner) public payable notExpired returns (uint256) { require(isETH(collateral), "ETH is not the specified collateral type"); require(hasVault(vaultOwner), "Vault does not exist"); emit ETHCollateralAdded(vaultOwner, msg.value, msg.sender); return _addCollateral(vaultOwner, msg.value); } /** * @notice If the collateral type is any ERC20, anyone can call this function any time before * expiry to increase the amount of collateral in a Vault. Can only transfer in the collateral asset. * Will fail if ETH is the collateral asset. * The user has to allow the contract to handle their ERC20 tokens on his behalf before these * functions are called. * Remember that adding ERC20 collateral even if no oTokens have been created can put the owner at a * risk of losing the collateral. Ensure that you issue and immediately sell the oTokens! * (Either call the createAndSell function in the oToken contract or batch the * addERC20Collateral, issueOTokens and sell transactions and ensure they happen atomically to protect * the end user). * @param vaultOwner the index of the Vault to which collateral will be added. * @param amt the amount of collateral to be transferred in. */ function addERC20Collateral(address payable vaultOwner, uint256 amt) public notExpired returns (uint256) { require( collateral.transferFrom(msg.sender, address(this), amt), "Could not transfer in collateral tokens" ); require(hasVault(vaultOwner), "Vault does not exist"); emit ERC20CollateralAdded(vaultOwner, amt, msg.sender); return _addCollateral(vaultOwner, amt); } /** * @notice Returns the amount of underlying to be transferred during an exercise call */ function underlyingRequiredToExercise(uint256 oTokensToExercise) public view returns (uint256) { uint64 underlyingPerOTokenExp = uint64( oTokenExchangeRate.exponent - underlyingExp ); return oTokensToExercise.mul(10**underlyingPerOTokenExp); } /** * @notice Returns true if exercise can be called */ function isExerciseWindow() public view returns (bool) { return ((block.timestamp >= expiry.sub(windowSize)) && (block.timestamp < expiry)); } /** * @notice Returns true if the oToken contract has expired */ function hasExpired() public view returns (bool) { return (block.timestamp >= expiry); } /** * @notice Called by anyone holding the oTokens and underlying during the * exercise window i.e. from `expiry - windowSize` time to `expiry` time. The caller * transfers in their oTokens and corresponding amount of underlying and gets * `strikePrice * oTokens` amount of collateral out. The collateral paid out is taken from * the each vault owner starting with the first and iterating until the oTokens to exercise * are found. * NOTE: This uses a for loop and hence could run out of gas if the array passed in is too big! * @param oTokensToExercise the number of oTokens being exercised. * @param vaultsToExerciseFrom the array of vaults to exercise from. */ function exercise( uint256 oTokensToExercise, address payable[] memory vaultsToExerciseFrom ) public payable { for (uint256 i = 0; i < vaultsToExerciseFrom.length; i++) { address payable vaultOwner = vaultsToExerciseFrom[i]; require( hasVault(vaultOwner), "Cannot exercise from a vault that doesn't exist" ); Vault storage vault = vaults[vaultOwner]; if (oTokensToExercise == 0) { return; } else if (vault.oTokensIssued >= oTokensToExercise) { _exercise(oTokensToExercise, vaultOwner); return; } else { oTokensToExercise = oTokensToExercise.sub(vault.oTokensIssued); _exercise(vault.oTokensIssued, vaultOwner); } } require( oTokensToExercise == 0, "Specified vaults have insufficient collateral" ); } /** * @notice This function allows the vault owner to remove their share of underlying after an exercise */ function removeUnderlying() public { require(hasVault(msg.sender), "Vault does not exist"); Vault storage vault = vaults[msg.sender]; require(vault.underlying > 0, "No underlying balance"); uint256 underlyingToTransfer = vault.underlying; vault.underlying = 0; transferUnderlying(msg.sender, underlyingToTransfer); emit RemoveUnderlying(underlyingToTransfer, msg.sender); } /** * @notice This function is called to issue the option tokens. Remember that issuing oTokens even if they * haven't been sold can put the owner at a risk of not making premiums on the oTokens. Ensure that you * issue and immidiately sell the oTokens! (Either call the createAndSell function in the oToken contract * of batch the issueOTokens transaction with a sell transaction and ensure it happens atomically). * @dev The owner of a Vault should only be able to have a max of * repo.collateral * collateralToStrike / (minminCollateralizationRatio * strikePrice) tokens issued. * @param oTokensToIssue The number of o tokens to issue * @param receiver The address to send the oTokens to */ function issueOTokens(uint256 oTokensToIssue, address receiver) public notExpired { //check that we're properly collateralized to mint this number, then call _mint(address account, uint256 amount) require(hasVault(msg.sender), "Vault does not exist"); Vault storage vault = vaults[msg.sender]; // checks that the vault is sufficiently collateralized uint256 newOTokensBalance = vault.oTokensIssued.add(oTokensToIssue); require(isSafe(vault.collateral, newOTokensBalance), "unsafe to mint"); // issue the oTokens vault.oTokensIssued = newOTokensBalance; _mint(receiver, oTokensToIssue); emit IssuedOTokens(receiver, oTokensToIssue, msg.sender); return; } /** * @notice Returns the vault for a given address * @param vaultOwner the owner of the Vault to return */ function getVault(address payable vaultOwner) public view returns (uint256, uint256, uint256, bool) { Vault storage vault = vaults[vaultOwner]; return ( vault.collateral, vault.oTokensIssued, vault.underlying, vault.owned ); } /** * @notice Returns true if the given ERC20 is ETH. * @param _ierc20 the ERC20 asset. */ function isETH(IERC20 _ierc20) public pure returns (bool) { return _ierc20 == IERC20(0); } /** * @notice allows the owner to burn their oTokens to increase the collateralization ratio of * their vault. * @param amtToBurn number of oTokens to burn * @dev only want to call this function before expiry. After expiry, no benefit to calling it. */ function burnOTokens(uint256 amtToBurn) public notExpired { require(hasVault(msg.sender), "Vault does not exist"); Vault storage vault = vaults[msg.sender]; vault.oTokensIssued = vault.oTokensIssued.sub(amtToBurn); _burn(msg.sender, amtToBurn); emit BurnOTokens(msg.sender, amtToBurn); } /** * @notice allows the owner to remove excess collateral from the vault before expiry. Removing collateral lowers * the collateralization ratio of the vault. * @param amtToRemove Amount of collateral to remove in 10^-18. */ function removeCollateral(uint256 amtToRemove) public notExpired { require(amtToRemove > 0, "Cannot remove 0 collateral"); require(hasVault(msg.sender), "Vault does not exist"); Vault storage vault = vaults[msg.sender]; require( amtToRemove <= getCollateral(msg.sender), "Can't remove more collateral than owned" ); // check that vault will remain safe after removing collateral uint256 newCollateralBalance = vault.collateral.sub(amtToRemove); require( isSafe(newCollateralBalance, vault.oTokensIssued), "Vault is unsafe" ); // remove the collateral vault.collateral = newCollateralBalance; transferCollateral(msg.sender, amtToRemove); emit RemoveCollateral(amtToRemove, msg.sender); } /** * @notice after expiry, each vault holder can get back their proportional share of collateral * from vaults that they own. * @dev The owner gets all of their collateral back if no exercise event took their collateral. */ function redeemVaultBalance() public { require(hasExpired(), "Can't collect collateral until expiry"); require(hasVault(msg.sender), "Vault does not exist"); // pay out owner their share Vault storage vault = vaults[msg.sender]; // To deal with lower precision uint256 collateralToTransfer = vault.collateral; uint256 underlyingToTransfer = vault.underlying; vault.collateral = 0; vault.oTokensIssued = 0; vault.underlying = 0; transferCollateral(msg.sender, collateralToTransfer); transferUnderlying(msg.sender, underlyingToTransfer); emit RedeemVaultBalance( collateralToTransfer, underlyingToTransfer, msg.sender ); } /** * This function returns the maximum amount of collateral liquidatable if the given vault is unsafe * @param vaultOwner The index of the vault to be liquidated */ function maxOTokensLiquidatable(address payable vaultOwner) public view returns (uint256) { if (isUnsafe(vaultOwner)) { Vault storage vault = vaults[vaultOwner]; uint256 maxCollateralLiquidatable = vault .collateral .mul(liquidationFactor.value) .div(10**uint256(-liquidationFactor.exponent)); uint256 one = 10**uint256(-liquidationIncentive.exponent); Number memory liqIncentive = Number( liquidationIncentive.value.add(one), liquidationIncentive.exponent ); return calculateOTokens(maxCollateralLiquidatable, liqIncentive); } else { return 0; } } /** * @notice This function can be called by anyone who notices a vault is undercollateralized. * The caller gets a reward for reducing the amount of oTokens in circulation. * @dev Liquidator comes with _oTokens. They get _oTokens * strikePrice * (incentive + fee) * amount of collateral out. They can liquidate a max of liquidationFactor * vault.collateral out * in one function call i.e. partial liquidations. * @param vaultOwner The index of the vault to be liquidated * @param oTokensToLiquidate The number of oTokens being taken out of circulation */ function liquidate(address payable vaultOwner, uint256 oTokensToLiquidate) public notExpired { require(hasVault(vaultOwner), "Vault does not exist"); Vault storage vault = vaults[vaultOwner]; // cannot liquidate a safe vault. require(isUnsafe(vaultOwner), "Vault is safe"); // Owner can't liquidate themselves require(msg.sender != vaultOwner, "Owner can't liquidate themselves"); uint256 amtCollateral = calculateCollateralToPay( oTokensToLiquidate, Number(1, 0) ); uint256 amtIncentive = calculateCollateralToPay( oTokensToLiquidate, liquidationIncentive ); uint256 amtCollateralToPay = amtCollateral.add(amtIncentive); // calculate the maximum amount of collateral that can be liquidated uint256 maxCollateralLiquidatable = vault.collateral.mul( liquidationFactor.value ); if (liquidationFactor.exponent > 0) { maxCollateralLiquidatable = maxCollateralLiquidatable.mul( 10**uint256(liquidationFactor.exponent) ); } else { maxCollateralLiquidatable = maxCollateralLiquidatable.div( 10**uint256(-1 * liquidationFactor.exponent) ); } require( amtCollateralToPay <= maxCollateralLiquidatable, "Can only liquidate liquidation factor at any given time" ); // deduct the collateral and oTokensIssued vault.collateral = vault.collateral.sub(amtCollateralToPay); vault.oTokensIssued = vault.oTokensIssued.sub(oTokensToLiquidate); // transfer the collateral and burn the _oTokens _burn(msg.sender, oTokensToLiquidate); transferCollateral(msg.sender, amtCollateralToPay); emit Liquidate(amtCollateralToPay, vaultOwner, msg.sender); } /** * @notice checks if a vault is unsafe. If so, it can be liquidated * @param vaultOwner The number of the vault to check * @return true or false */ function isUnsafe(address payable vaultOwner) public view returns (bool) { bool stillUnsafe = !isSafe( getCollateral(vaultOwner), getOTokensIssued(vaultOwner) ); return stillUnsafe; } /** * @notice This function returns if an -30 <= exponent <= 30 */ function isWithinExponentRange(int32 val) internal pure returns (bool) { return ((val <= 30) && (val >= -30)); } /** * @notice This function calculates and returns the amount of collateral in the vault */ function getCollateral(address payable vaultOwner) internal view returns (uint256) { Vault storage vault = vaults[vaultOwner]; return vault.collateral; } /** * @notice This function calculates and returns the amount of puts issued by the Vault */ function getOTokensIssued(address payable vaultOwner) internal view returns (uint256) { Vault storage vault = vaults[vaultOwner]; return vault.oTokensIssued; } /** * @notice Called by anyone holding the oTokens and underlying during the * exercise window i.e. from `expiry - windowSize` time to `expiry` time. The caller * transfers in their oTokens and corresponding amount of underlying and gets * `strikePrice * oTokens` amount of collateral out. The collateral paid out is taken from * the specified vault holder. At the end of the expiry window, the vault holder can redeem their balance * of collateral. The vault owner can withdraw their underlying at any time. * The user has to allow the contract to handle their oTokens and underlying on his behalf before these functions are called. * @param oTokensToExercise the number of oTokens being exercised. * @param vaultToExerciseFrom the address of the vaultOwner to take collateral from. * @dev oTokenExchangeRate is the number of underlying tokens that 1 oToken protects. */ function _exercise( uint256 oTokensToExercise, address payable vaultToExerciseFrom ) internal { // 1. before exercise window: revert require( isExerciseWindow(), "Can't exercise outside of the exercise window" ); require(hasVault(vaultToExerciseFrom), "Vault does not exist"); Vault storage vault = vaults[vaultToExerciseFrom]; require(oTokensToExercise > 0, "Can't exercise 0 oTokens"); // Check correct amount of oTokens passed in) require( oTokensToExercise <= vault.oTokensIssued, "Can't exercise more oTokens than the owner has" ); // Ensure person calling has enough oTokens require( balanceOf(msg.sender) >= oTokensToExercise, "Not enough oTokens" ); // 1. Check sufficient underlying // 1.1 update underlying balances uint256 amtUnderlyingToPay = underlyingRequiredToExercise( oTokensToExercise ); vault.underlying = vault.underlying.add(amtUnderlyingToPay); // 2. Calculate Collateral to pay // 2.1 Payout enough collateral to get (strikePrice * oTokens) amount of collateral uint256 amtCollateralToPay = calculateCollateralToPay( oTokensToExercise, Number(1, 0) ); // 2.2 Take a small fee on every exercise uint256 amtFee = calculateCollateralToPay( oTokensToExercise, transactionFee ); totalFee = totalFee.add(amtFee); uint256 totalCollateralToPay = amtCollateralToPay.add(amtFee); require( totalCollateralToPay <= vault.collateral, "Vault underwater, can't exercise" ); // 3. Update collateral + oToken balances vault.collateral = vault.collateral.sub(totalCollateralToPay); vault.oTokensIssued = vault.oTokensIssued.sub(oTokensToExercise); // 4. Transfer in underlying, burn oTokens + pay out collateral // 4.1 Transfer in underlying if (isETH(underlying)) { require(msg.value == amtUnderlyingToPay, "Incorrect msg.value"); } else { require( underlying.transferFrom( msg.sender, address(this), amtUnderlyingToPay ), "Could not transfer in tokens" ); } // 4.2 burn oTokens _burn(msg.sender, oTokensToExercise); // 4.3 Pay out collateral transferCollateral(msg.sender, amtCollateralToPay); emit Exercise( amtUnderlyingToPay, amtCollateralToPay, msg.sender, vaultToExerciseFrom ); } /** * @notice adds `_amt` collateral to `vaultOwner` and returns the new balance of the vault * @param vaultOwner the index of the vault * @param amt the amount of collateral to add */ function _addCollateral(address payable vaultOwner, uint256 amt) internal notExpired returns (uint256) { Vault storage vault = vaults[vaultOwner]; vault.collateral = vault.collateral.add(amt); return vault.collateral; } /** * @notice checks if a hypothetical vault is safe with the given collateralAmt and oTokensIssued * @param collateralAmt The amount of collateral the hypothetical vault has * @param oTokensIssued The amount of oTokens generated by the hypothetical vault * @return true or false */ function isSafe(uint256 collateralAmt, uint256 oTokensIssued) internal view returns (bool) { // get price from Oracle uint256 collateralToEthPrice = getPrice(address(collateral)); uint256 strikeToEthPrice = getPrice(address(strike)); // check `oTokensIssued * minCollateralizationRatio * strikePrice <= collAmt * collateralToStrikePrice` uint256 leftSideVal = oTokensIssued .mul(minCollateralizationRatio.value) .mul(strikePrice.value); int32 leftSideExp = minCollateralizationRatio.exponent + strikePrice.exponent; uint256 rightSideVal = (collateralAmt.mul(collateralToEthPrice)).div( strikeToEthPrice ); int32 rightSideExp = collateralExp; uint256 exp = 0; bool stillSafe = false; if (rightSideExp < leftSideExp) { exp = uint256(leftSideExp - rightSideExp); stillSafe = leftSideVal.mul(10**exp) <= rightSideVal; } else { exp = uint256(rightSideExp - leftSideExp); stillSafe = leftSideVal <= rightSideVal.mul(10**exp); } return stillSafe; } /** * This function returns the maximum amount of oTokens that can safely be issued against the specified amount of collateral. * @param collateralAmt The amount of collateral against which oTokens will be issued. */ function maxOTokensIssuable(uint256 collateralAmt) public view returns (uint256) { return calculateOTokens(collateralAmt, minCollateralizationRatio); } /** * @notice This function is used to calculate the amount of tokens that can be issued. * @dev The amount of oTokens is determined by: * oTokensIssued <= collateralAmt * collateralToStrikePrice / (proportion * strikePrice) * @param collateralAmt The amount of collateral * @param proportion The proportion of the collateral to pay out. If 100% of collateral * should be paid out, pass in Number(1, 0). The proportion might be less than 100% if * you are calculating fees. */ function calculateOTokens(uint256 collateralAmt, Number memory proportion) internal view returns (uint256) { uint256 collateralToEthPrice = getPrice(address(collateral)); uint256 strikeToEthPrice = getPrice(address(strike)); // oTokensIssued <= collAmt * collateralToStrikePrice / (proportion * strikePrice) uint256 denomVal = proportion.value.mul(strikePrice.value); int32 denomExp = proportion.exponent + strikePrice.exponent; uint256 numeratorVal = (collateralAmt.mul(collateralToEthPrice)).div( strikeToEthPrice ); int32 numeratorExp = collateralExp; uint256 exp = 0; uint256 numOptions = 0; if (numeratorExp < denomExp) { exp = uint256(denomExp - numeratorExp); numOptions = numeratorVal.div(denomVal.mul(10**exp)); } else { exp = uint256(numeratorExp - denomExp); numOptions = numeratorVal.mul(10**exp).div(denomVal); } return numOptions; } /** * @notice This function calculates the amount of collateral to be paid out. * @dev The amount of collateral to paid out is determined by: * (proportion * strikePrice * strikeToCollateralPrice * oTokens) amount of collateral. * @param _oTokens The number of oTokens. * @param proportion The proportion of the collateral to pay out. If 100% of collateral * should be paid out, pass in Number(1, 0). The proportion might be less than 100% if * you are calculating fees. */ function calculateCollateralToPay( uint256 _oTokens, Number memory proportion ) internal view returns (uint256) { // Get price from oracle uint256 collateralToEthPrice = getPrice(address(collateral)); uint256 strikeToEthPrice = getPrice(address(strike)); // calculate how much should be paid out uint256 amtCollateralToPayInEthNum = _oTokens .mul(strikePrice.value) .mul(proportion.value) .mul(strikeToEthPrice); int32 amtCollateralToPayExp = strikePrice.exponent + proportion.exponent - collateralExp; uint256 amtCollateralToPay = 0; if (amtCollateralToPayExp > 0) { uint32 exp = uint32(amtCollateralToPayExp); amtCollateralToPay = amtCollateralToPayInEthNum.mul(10**exp).div( collateralToEthPrice ); } else { uint32 exp = uint32(-1 * amtCollateralToPayExp); amtCollateralToPay = (amtCollateralToPayInEthNum.div(10**exp)).div( collateralToEthPrice ); } return amtCollateralToPay; } /** * @notice This function transfers `amt` collateral to `_addr` * @param _addr The address to send the collateral to * @param _amt The amount of the collateral to pay out. */ function transferCollateral(address payable _addr, uint256 _amt) internal { if (isETH(collateral)) { _addr.transfer(_amt); } else { collateral.transfer(_addr, _amt); } } /** * @notice This function transfers `amt` underlying to `_addr` * @param _addr The address to send the underlying to * @param _amt The amount of the underlying to pay out. */ function transferUnderlying(address payable _addr, uint256 _amt) internal { if (isETH(underlying)) { _addr.transfer(_amt); } else { underlying.transfer(_addr, _amt); } } /** * @notice This function gets the price ETH (wei) to asset price. * @param asset The address of the asset to get the price of */ function getPrice(address asset) internal view returns (uint256) { if (address(collateral) == address(strike)) { return 1; } else if (asset == address(0)) { return (10**18); } else { return COMPOUND_ORACLE.getPrice(asset); } } } // File: contracts/oToken.sol pragma solidity 0.5.10; /** * @title Opyn's Options Contract * @author Opyn */ contract oToken is OptionsContract { /** * @param _collateral The collateral asset * @param _collExp The precision of the collateral (-18 if ETH) * @param _underlying The asset that is being protected * @param _underlyingExp The precision of the underlying asset * @param _oTokenExchangeExp The precision of the `amount of underlying` that 1 oToken protects * @param _strikePrice The amount of strike asset that will be paid out * @param _strikeExp The precision of the strike asset (-18 if ETH) * @param _strike The asset in which the insurance is calculated * @param _expiry The time at which the insurance expires * @param _optionsExchange The contract which interfaces with the exchange + oracle * @param _oracleAddress The address of the oracle * @param _windowSize UNIX time. Exercise window is from `expiry - _windowSize` to `expiry`. */ constructor( IERC20 _collateral, int32 _collExp, IERC20 _underlying, int32 _underlyingExp, int32 _oTokenExchangeExp, uint256 _strikePrice, int32 _strikeExp, IERC20 _strike, uint256 _expiry, OptionsExchange _optionsExchange, address _oracleAddress, uint256 _windowSize ) public OptionsContract( _collateral, _collExp, _underlying, _underlyingExp, _oTokenExchangeExp, _strikePrice, _strikeExp, _strike, _expiry, _optionsExchange, _oracleAddress, _windowSize ) {} /** * @notice opens a Vault, adds ETH collateral, and mints new oTokens in one step * Remember that creating oTokens can put the owner at a risk of losing the collateral * if an exercise event happens. * The sell function provides the owner a chance to earn premiums. * Ensure that you create and immediately sell oTokens atmoically. * @param amtToCreate number of oTokens to create * @param receiver address to send the Options to */ function createETHCollateralOption(uint256 amtToCreate, address receiver) external payable { openVault(); addETHCollateralOption(amtToCreate, receiver); } /** * @notice adds ETH collateral, and mints new oTokens in one step to an existing Vault * Remember that creating oTokens can put the owner at a risk of losing the collateral * if an exercise event happens. * The sell function provides the owner a chance to earn premiums. * Ensure that you create and immediately sell oTokens atmoically. * @param amtToCreate number of oTokens to create * @param receiver address to send the Options to */ function addETHCollateralOption(uint256 amtToCreate, address receiver) public payable { addETHCollateral(msg.sender); issueOTokens(amtToCreate, receiver); } /** * @notice opens a Vault, adds ETH collateral, mints new oTokens and sell in one step * @param amtToCreate number of oTokens to create * @param receiver address to receive the premiums */ function createAndSellETHCollateralOption( uint256 amtToCreate, address payable receiver ) external payable { openVault(); addETHCollateralOption(amtToCreate, address(this)); this.approve(address(optionsExchange), amtToCreate); optionsExchange.sellOTokens( receiver, address(this), address(0), amtToCreate ); } /** * @notice adds ETH collateral to an existing Vault, and mints new oTokens and sells the oTokens in one step * @param amtToCreate number of oTokens to create * @param receiver address to send the Options to */ function addAndSellETHCollateralOption( uint256 amtToCreate, address payable receiver ) public payable { addETHCollateral(msg.sender); issueOTokens(amtToCreate, address(this)); this.approve(address(optionsExchange), amtToCreate); optionsExchange.sellOTokens( receiver, address(this), address(0), amtToCreate ); } /** * @notice opens a Vault, adds ERC20 collateral, and mints new oTokens in one step * Remember that creating oTokens can put the owner at a risk of losing the collateral * if an exercise event happens. * The sell function provides the owner a chance to earn premiums. * Ensure that you create and immediately sell oTokens atmoically. * @param amtToCreate number of oTokens to create * @param amtCollateral amount of collateral added * @param receiver address to send the Options to */ function createERC20CollateralOption( uint256 amtToCreate, uint256 amtCollateral, address receiver ) external { openVault(); addERC20CollateralOption(amtToCreate, amtCollateral, receiver); } /** * @notice adds ERC20 collateral, and mints new oTokens in one step * Remember that creating oTokens can put the owner at a risk of losing the collateral * if an exercise event happens. * The sell function provides the owner a chance to earn premiums. * Ensure that you create and immediately sell oTokens atmoically. * @param amtToCreate number of oTokens to create * @param amtCollateral amount of collateral added * @param receiver address to send the Options to */ function addERC20CollateralOption( uint256 amtToCreate, uint256 amtCollateral, address receiver ) public { addERC20Collateral(msg.sender, amtCollateral); issueOTokens(amtToCreate, receiver); } /** * @notice opens a Vault, adds ERC20 collateral, mints new oTokens and sells the oTokens in one step * @param amtToCreate number of oTokens to create * @param amtCollateral amount of collateral added * @param receiver address to send the Options to */ function createAndSellERC20CollateralOption( uint256 amtToCreate, uint256 amtCollateral, address payable receiver ) external { openVault(); addERC20CollateralOption(amtToCreate, amtCollateral, address(this)); this.approve(address(optionsExchange), amtToCreate); optionsExchange.sellOTokens( receiver, address(this), address(0), amtToCreate ); } /** * @notice adds ERC20 collateral, mints new oTokens and sells the oTokens in one step * @param amtToCreate number of oTokens to create * @param amtCollateral amount of collateral added * @param receiver address to send the Options to */ function addAndSellERC20CollateralOption( uint256 amtToCreate, uint256 amtCollateral, address payable receiver ) public { addERC20Collateral(msg.sender, amtCollateral); issueOTokens(amtToCreate, address(this)); this.approve(address(optionsExchange), amtToCreate); optionsExchange.sellOTokens( receiver, address(this), address(0), amtToCreate ); } }
File 2 of 7: FiatTokenProxy
pragma solidity ^0.4.24; // File: zos-lib/contracts/upgradeability/Proxy.sol /** * @title Proxy * @dev Implements delegation of calls to other contracts, with proper * forwarding of return values and bubbling of failures. * It defines a fallback function that delegates all calls to the address * returned by the abstract _implementation() internal function. */ contract Proxy { /** * @dev Fallback function. * Implemented entirely in `_fallback`. */ function () payable external { _fallback(); } /** * @return The Address of the implementation. */ function _implementation() internal view returns (address); /** * @dev Delegates execution to an implementation contract. * This is a low level function that doesn't return to its internal call site. * It will return to the external caller whatever the implementation returns. * @param implementation Address to delegate. */ function _delegate(address implementation) internal { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize) } default { return(0, returndatasize) } } } /** * @dev Function that is run as the first thing in the fallback function. * Can be redefined in derived contracts to add functionality. * Redefinitions must call super._willFallback(). */ function _willFallback() internal { } /** * @dev fallback implementation. * Extracted to enable manual triggering. */ function _fallback() internal { _willFallback(); _delegate(_implementation()); } } // File: openzeppelin-solidity/contracts/AddressUtils.sol /** * Utility library of inline functions on addresses */ library AddressUtils { /** * Returns whether the target address is a contract * @dev This function will return false if invoked during the constructor of a contract, * as the code is not actually created until after the constructor finishes. * @param addr address to check * @return whether the target address is a contract */ function isContract(address addr) internal view returns (bool) { uint256 size; // XXX Currently there is no better way to check if there is a contract in an address // than to check the size of the code at that address. // See https://ethereum.stackexchange.com/a/14016/36603 // for more details about how this works. // TODO Check this again before the Serenity release, because all addresses will be // contracts then. // solium-disable-next-line security/no-inline-assembly assembly { size := extcodesize(addr) } return size > 0; } } // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol /** * @title UpgradeabilityProxy * @dev This contract implements a proxy that allows to change the * implementation address to which it will delegate. * Such a change is called an implementation upgrade. */ contract UpgradeabilityProxy is Proxy { /** * @dev Emitted when the implementation is upgraded. * @param implementation Address of the new implementation. */ event Upgraded(address implementation); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is * validated in the constructor. */ bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3; /** * @dev Contract constructor. * @param _implementation Address of the initial implementation. */ constructor(address _implementation) public { assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation")); _setImplementation(_implementation); } /** * @dev Returns the current implementation. * @return Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Upgrades the proxy to a new implementation. * @param newImplementation Address of the new implementation. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Sets the implementation address of the proxy. * @param newImplementation Address of the new implementation. */ function _setImplementation(address newImplementation) private { require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); bytes32 slot = IMPLEMENTATION_SLOT; assembly { sstore(slot, newImplementation) } } } // File: zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol /** * @title AdminUpgradeabilityProxy * @dev This contract combines an upgradeability proxy with an authorization * mechanism for administrative tasks. * All external functions in this contract must be guarded by the * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity * feature proposal that would enable this to be done automatically. */ contract AdminUpgradeabilityProxy is UpgradeabilityProxy { /** * @dev Emitted when the administration has been transferred. * @param previousAdmin Address of the previous admin. * @param newAdmin Address of the new admin. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is * validated in the constructor. */ bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b; /** * @dev Modifier to check whether the `msg.sender` is the admin. * If it is, it will run the function. Otherwise, it will delegate the call * to the implementation. */ modifier ifAdmin() { if (msg.sender == _admin()) { _; } else { _fallback(); } } /** * Contract constructor. * It sets the `msg.sender` as the proxy administrator. * @param _implementation address of the initial implementation. */ constructor(address _implementation) UpgradeabilityProxy(_implementation) public { assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin")); _setAdmin(msg.sender); } /** * @return The address of the proxy admin. */ function admin() external view ifAdmin returns (address) { return _admin(); } /** * @return The address of the implementation. */ function implementation() external view ifAdmin returns (address) { return _implementation(); } /** * @dev Changes the admin of the proxy. * Only the current admin can call this function. * @param newAdmin Address to transfer proxy administration to. */ 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); } /** * @dev Upgrade the backing implementation of the proxy. * Only the admin can call this function. * @param newImplementation Address of the new implementation. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeTo(newImplementation); } /** * @dev Upgrade the backing implementation of the proxy and call a function * on the new implementation. * This is useful to initialize the proxied contract. * @param newImplementation Address of the new implementation. * @param data Data to send as msg.data in the low level call. * It should include the signature and the parameters of the function to be * called, as described in * https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector-and-argument-encoding. */ function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin { _upgradeTo(newImplementation); require(address(this).call.value(msg.value)(data)); } /** * @return The admin slot. */ function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { adm := sload(slot) } } /** * @dev Sets the address of the proxy admin. * @param newAdmin Address of the new proxy admin. */ function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SLOT; assembly { sstore(slot, newAdmin) } } /** * @dev Only fall back when the sender is not the admin. */ function _willFallback() internal { require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin"); super._willFallback(); } } // File: contracts/FiatTokenProxy.sol /** * Copyright CENTRE SECZ 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished to * do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity ^0.4.24; /** * @title FiatTokenProxy * @dev This contract proxies FiatToken calls and enables FiatToken upgrades */ contract FiatTokenProxy is AdminUpgradeabilityProxy { constructor(address _implementation) public AdminUpgradeabilityProxy(_implementation) { } }
File 3 of 7: OptionsExchange
// File: @openzeppelin/contracts/GSN/Context.sol pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts/math/SafeMath.sol 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) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); 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-contracts/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) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); 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) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: @openzeppelin/contracts/token/ERC20/ERC20.sol pragma solidity ^0.5.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20Mintable}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for `sender`'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal { 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); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } } // File: contracts/lib/CompoundOracleInterface.sol pragma solidity ^0.5.0; // AT MAINNET ADDRESS: 0x02557a5E05DeFeFFD4cAe6D83eA3d173B272c904 contract CompoundOracleInterface { // returns asset:eth -- to get USDC:eth, have to do 10**24/result, constructor() public { } /** * @notice retrieves price of an asset * @dev function to get price for an asset * @param asset Asset for which to get the price * @return uint mantissa of asset price (scaled by 1e18) or zero if unset or contract paused */ function getPrice(address asset) public view returns (uint); function getUnderlyingPrice(ERC20 cToken) public view returns (uint); // function getPrice(address asset) public view returns (uint) { // return 527557000000000; // } } // File: contracts/lib/UniswapExchangeInterface.sol pragma solidity 0.5.10; // Solidity Interface contract UniswapExchangeInterface { // Address of ERC20 token sold on this exchange function tokenAddress() external view returns (address token); // Address of Uniswap Factory function factoryAddress() external view returns (address factory); // Provide Liquidity function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256); function removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline) external returns (uint256, uint256); // Get Prices function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought); function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold); function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought); function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold); // Trade ETH to ERC20 function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256 tokens_bought); function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256 tokens_bought); function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256 eth_sold); function ethToTokenTransferOutput(uint256 tokens_bought, uint256 deadline, address recipient) external payable returns (uint256 eth_sold); // Trade ERC20 to ETH function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256 eth_bought); function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline, address recipient) external returns (uint256 eth_bought); function tokenToEthSwapOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline) external returns (uint256 tokens_sold); function tokenToEthTransferOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline, address recipient) external returns (uint256 tokens_sold); // Trade ERC20 to ERC20 function tokenToTokenSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address token_addr) external returns (uint256 tokens_bought); function tokenToTokenTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_bought); function tokenToTokenSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address token_addr) external returns (uint256 tokens_sold); function tokenToTokenTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_sold); // Trade ERC20 to Custom Pool function tokenToExchangeSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address exchange_addr) external returns (uint256 tokens_bought); function tokenToExchangeTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_bought); function tokenToExchangeSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address exchange_addr) external returns (uint256 tokens_sold); function tokenToExchangeTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_sold); // ERC20 comaptibility for liquidity tokens bytes32 public name; bytes32 public symbol; uint256 public decimals; function transfer(address _to, uint256 _value) external returns (bool); function transferFrom(address _from, address _to, uint256 value) external returns (bool); function approve(address _spender, uint256 _value) external returns (bool); function allowance(address _owner, address _spender) external view returns (uint256); function balanceOf(address _owner) external view returns (uint256); function totalSupply() external view returns (uint256); // Never use function setup(address token_addr) external; } // File: contracts/lib/UniswapFactoryInterface.sol pragma solidity 0.5.10; // Solidity Interface contract UniswapFactoryInterface { // Public Variables address public exchangeTemplate; uint256 public tokenCount; // // Create Exchange function createExchange(address token) external returns (address exchange); // Get Exchange and Token Info function getExchange(address token) external view returns (address exchange); function getToken(address exchange) external view returns (address token); function getTokenWithId(uint256 tokenId) external view returns (address token); // Never use function initializeFactory(address template) external; // function createExchange(address token) external returns (address exchange) { // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } // // Get Exchange and Token Info // function getExchange(address token) external view returns (address exchange){ // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } // function getToken(address exchange) external view returns (address token) { // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } // function getTokenWithId(uint256 tokenId) external view returns (address token) { // return 0x06D014475F84Bb45b9cdeD1Cf3A1b8FE3FbAf128; // } } // File: contracts/OptionsUtils.sol pragma solidity 0.5.10; contract OptionsUtils { // defauls are for mainnet UniswapFactoryInterface public UNISWAP_FACTORY; CompoundOracleInterface public COMPOUND_ORACLE; constructor(address _uniswapFactory, address _compoundOracle) public { UNISWAP_FACTORY = UniswapFactoryInterface(_uniswapFactory); COMPOUND_ORACLE = CompoundOracleInterface(_compoundOracle); } // TODO: for now gets Uniswap, later update to get other exchanges function getExchange(address _token) public view returns (UniswapExchangeInterface) { if (address(UNISWAP_FACTORY.getExchange(_token)) == address(0)) { revert("No payout exchange"); } UniswapExchangeInterface exchange = UniswapExchangeInterface( UNISWAP_FACTORY.getExchange(_token) ); return exchange; } function isETH(IERC20 _ierc20) public pure returns (bool) { return _ierc20 == IERC20(0); } } // File: contracts/OptionsExchange.sol pragma solidity 0.5.10; contract OptionsExchange { uint256 constant LARGE_BLOCK_SIZE = 1651753129000; uint256 constant LARGE_APPROVAL_NUMBER = 10**30; UniswapFactoryInterface public UNISWAP_FACTORY; constructor(address _uniswapFactory) public { UNISWAP_FACTORY = UniswapFactoryInterface(_uniswapFactory); } /*** Events ***/ event SellOTokens( address seller, address payable receiver, address oTokenAddress, address payoutTokenAddress, uint256 oTokensToSell, uint256 payoutTokensReceived ); event BuyOTokens( address buyer, address payable receiver, address oTokenAddress, address paymentTokenAddress, uint256 oTokensToBuy, uint256 premiumPaid ); /** * @notice This function sells oTokens on Uniswap and sends back payoutTokens to the receiver * @param receiver The address to send the payout tokens back to * @param oTokenAddress The address of the oToken to sell * @param payoutTokenAddress The address of the token to receive the premiums in * @param oTokensToSell The number of oTokens to sell */ function sellOTokens( address payable receiver, address oTokenAddress, address payoutTokenAddress, uint256 oTokensToSell ) public { // @note: first need to bootstrap the uniswap exchange to get the address. IERC20 oToken = IERC20(oTokenAddress); IERC20 payoutToken = IERC20(payoutTokenAddress); oToken.transferFrom(msg.sender, address(this), oTokensToSell); uint256 payoutTokensReceived = uniswapSellOToken( oToken, payoutToken, oTokensToSell, receiver ); emit SellOTokens( msg.sender, receiver, oTokenAddress, payoutTokenAddress, oTokensToSell, payoutTokensReceived ); } /** * @notice This function buys oTokens on Uniswap and using paymentTokens from the receiver * @param receiver The address to send the oTokens back to * @param oTokenAddress The address of the oToken to buy * @param paymentTokenAddress The address of the token to pay the premiums in * @param oTokensToBuy The number of oTokens to buy */ function buyOTokens( address payable receiver, address oTokenAddress, address paymentTokenAddress, uint256 oTokensToBuy ) public payable { IERC20 oToken = IERC20(oTokenAddress); IERC20 paymentToken = IERC20(paymentTokenAddress); uniswapBuyOToken(paymentToken, oToken, oTokensToBuy, receiver); } /** * @notice This function calculates the amount of premiums that the seller * will receive if they sold oTokens on Uniswap * @param oTokenAddress The address of the oToken to sell * @param payoutTokenAddress The address of the token to receive the premiums in * @param oTokensToSell The number of oTokens to sell */ function premiumReceived( address oTokenAddress, address payoutTokenAddress, uint256 oTokensToSell ) public view returns (uint256) { // get the amount of ETH that will be paid out if oTokensToSell is sold. UniswapExchangeInterface oTokenExchange = getExchange(oTokenAddress); uint256 ethReceived = oTokenExchange.getTokenToEthInputPrice( oTokensToSell ); if (!isETH(IERC20(payoutTokenAddress))) { // get the amount of payout tokens that will be received if the ethRecieved is sold. UniswapExchangeInterface payoutExchange = getExchange( payoutTokenAddress ); return payoutExchange.getEthToTokenInputPrice(ethReceived); } return ethReceived; } /** * @notice This function calculates the premiums to be paid if a buyer wants to * buy oTokens on Uniswap * @param oTokenAddress The address of the oToken to buy * @param paymentTokenAddress The address of the token to pay the premiums in * @param oTokensToBuy The number of oTokens to buy */ function premiumToPay( address oTokenAddress, address paymentTokenAddress, uint256 oTokensToBuy ) public view returns (uint256) { // get the amount of ETH that needs to be paid for oTokensToBuy. UniswapExchangeInterface oTokenExchange = getExchange(oTokenAddress); uint256 ethToPay = oTokenExchange.getEthToTokenOutputPrice( oTokensToBuy ); if (!isETH(IERC20(paymentTokenAddress))) { // get the amount of paymentTokens that needs to be paid to get the desired ethToPay. UniswapExchangeInterface paymentTokenExchange = getExchange( paymentTokenAddress ); return paymentTokenExchange.getTokenToEthOutputPrice(ethToPay); } return ethToPay; } function uniswapSellOToken( IERC20 oToken, IERC20 payoutToken, uint256 _amt, address payable _transferTo ) internal returns (uint256) { require(!isETH(oToken), "Can only sell oTokens"); UniswapExchangeInterface exchange = getExchange(address(oToken)); if (isETH(payoutToken)) { //Token to ETH oToken.approve(address(exchange), _amt); return exchange.tokenToEthTransferInput( _amt, 1, LARGE_BLOCK_SIZE, _transferTo ); } else { //Token to Token oToken.approve(address(exchange), _amt); return exchange.tokenToTokenTransferInput( _amt, 1, 1, LARGE_BLOCK_SIZE, _transferTo, address(payoutToken) ); } } function uniswapBuyOToken( IERC20 paymentToken, IERC20 oToken, uint256 _amt, address payable _transferTo ) public returns (uint256) { require(!isETH(oToken), "Can only buy oTokens"); if (!isETH(paymentToken)) { UniswapExchangeInterface exchange = getExchange( address(paymentToken) ); uint256 paymentTokensToTransfer = premiumToPay( address(oToken), address(paymentToken), _amt ); paymentToken.transferFrom( msg.sender, address(this), paymentTokensToTransfer ); // Token to Token paymentToken.approve(address(exchange), LARGE_APPROVAL_NUMBER); emit BuyOTokens( msg.sender, _transferTo, address(oToken), address(paymentToken), _amt, paymentTokensToTransfer ); return exchange.tokenToTokenTransferInput( paymentTokensToTransfer, 1, 1, LARGE_BLOCK_SIZE, _transferTo, address(oToken) ); } else { // ETH to Token UniswapExchangeInterface exchange = UniswapExchangeInterface( UNISWAP_FACTORY.getExchange(address(oToken)) ); uint256 ethToTransfer = exchange.getEthToTokenOutputPrice(_amt); emit BuyOTokens( msg.sender, _transferTo, address(oToken), address(paymentToken), _amt, ethToTransfer ); return exchange.ethToTokenTransferOutput.value(ethToTransfer)( _amt, LARGE_BLOCK_SIZE, _transferTo ); } } function getExchange(address _token) internal view returns (UniswapExchangeInterface) { UniswapExchangeInterface exchange = UniswapExchangeInterface( UNISWAP_FACTORY.getExchange(_token) ); if (address(exchange) == address(0)) { revert("No payout exchange"); } return exchange; } function isETH(IERC20 _ierc20) internal pure returns (bool) { return _ierc20 == IERC20(0); } function() external payable { // to get ether from uniswap exchanges } }
File 4 of 7: Vyper_contract
# @title Uniswap Exchange Interface V1 # @notice Source code found at https://github.com/uniswap # @notice Use at your own risk contract Factory(): def getExchange(token_addr: address) -> address: constant contract Exchange(): def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): constant def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: modifying def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): modifying TokenPurchase: event({buyer: indexed(address), eth_sold: indexed(uint256(wei)), tokens_bought: indexed(uint256)}) EthPurchase: event({buyer: indexed(address), tokens_sold: indexed(uint256), eth_bought: indexed(uint256(wei))}) AddLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) RemoveLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) name: public(bytes32) # Uniswap V1 symbol: public(bytes32) # UNI-V1 decimals: public(uint256) # 18 totalSupply: public(uint256) # total number of UNI in existence balances: uint256[address] # UNI balance of an address allowances: (uint256[address])[address] # UNI allowance of one address on another token: address(ERC20) # address of the ERC20 token traded on this contract factory: Factory # interface for the factory that created this contract # @dev This function acts as a contract constructor which is not currently supported in contracts deployed # using create_with_code_of(). It is called once by the factory during contract creation. @public def setup(token_addr: address): assert (self.factory == ZERO_ADDRESS and self.token == ZERO_ADDRESS) and token_addr != ZERO_ADDRESS self.factory = msg.sender self.token = token_addr self.name = 0x556e697377617020563100000000000000000000000000000000000000000000 self.symbol = 0x554e492d56310000000000000000000000000000000000000000000000000000 self.decimals = 18 # @notice Deposit ETH and Tokens (self.token) at current ratio to mint UNI tokens. # @dev min_liquidity does nothing when total UNI supply is 0. # @param min_liquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0. # @param max_tokens Maximum number of tokens deposited. Deposits max amount if total UNI supply is 0. # @param deadline Time after which this transaction can no longer be executed. # @return The amount of UNI minted. @public @payable def addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256: assert deadline > block.timestamp and (max_tokens > 0 and msg.value > 0) total_liquidity: uint256 = self.totalSupply if total_liquidity > 0: assert min_liquidity > 0 eth_reserve: uint256(wei) = self.balance - msg.value token_reserve: uint256 = self.token.balanceOf(self) token_amount: uint256 = msg.value * token_reserve / eth_reserve + 1 liquidity_minted: uint256 = msg.value * total_liquidity / eth_reserve assert max_tokens >= token_amount and liquidity_minted >= min_liquidity self.balances[msg.sender] += liquidity_minted self.totalSupply = total_liquidity + liquidity_minted assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, liquidity_minted) return liquidity_minted else: assert (self.factory != ZERO_ADDRESS and self.token != ZERO_ADDRESS) and msg.value >= 1000000000 assert self.factory.getExchange(self.token) == self token_amount: uint256 = max_tokens initial_liquidity: uint256 = as_unitless_number(self.balance) self.totalSupply = initial_liquidity self.balances[msg.sender] = initial_liquidity assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, initial_liquidity) return initial_liquidity # @dev Burn UNI tokens to withdraw ETH and Tokens at current ratio. # @param amount Amount of UNI burned. # @param min_eth Minimum ETH withdrawn. # @param min_tokens Minimum Tokens withdrawn. # @param deadline Time after which this transaction can no longer be executed. # @return The amount of ETH and Tokens withdrawn. @public def removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256): assert (amount > 0 and deadline > block.timestamp) and (min_eth > 0 and min_tokens > 0) total_liquidity: uint256 = self.totalSupply assert total_liquidity > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_amount: uint256(wei) = amount * self.balance / total_liquidity token_amount: uint256 = amount * token_reserve / total_liquidity assert eth_amount >= min_eth and token_amount >= min_tokens self.balances[msg.sender] -= amount self.totalSupply = total_liquidity - amount send(msg.sender, eth_amount) assert self.token.transfer(msg.sender, token_amount) log.RemoveLiquidity(msg.sender, eth_amount, token_amount) log.Transfer(msg.sender, ZERO_ADDRESS, amount) return eth_amount, token_amount # @dev Pricing function for converting between ETH and Tokens. # @param input_amount Amount of ETH or Tokens being sold. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens bought. @private @constant def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 input_amount_with_fee: uint256 = input_amount * 997 numerator: uint256 = input_amount_with_fee * output_reserve denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee return numerator / denominator # @dev Pricing function for converting between ETH and Tokens. # @param output_amount Amount of ETH or Tokens being bought. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens sold. @private @constant def getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 numerator: uint256 = input_reserve * output_amount * 1000 denominator: uint256 = (output_reserve - output_amount) * 997 return numerator / denominator + 1 @private def ethToTokenInput(eth_sold: uint256(wei), min_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and (eth_sold > 0 and min_tokens > 0) token_reserve: uint256 = self.token.balanceOf(self) tokens_bought: uint256 = self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance - eth_sold), token_reserve) assert tokens_bought >= min_tokens assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, eth_sold, tokens_bought) return tokens_bought # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value). # @dev User cannot specify minimum output or deadline. @public @payable def __default__(): self.ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender) # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value) and minimum output. # @param min_tokens Minimum Tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens bought. @public @payable def ethToTokenSwapInput(min_tokens: uint256, deadline: timestamp) -> uint256: return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies exact input (msg.value) and minimum output # @param min_tokens Minimum Tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output Tokens. # @return Amount of Tokens bought. @public @payable def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, recipient) @private def ethToTokenOutput(tokens_bought: uint256, max_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance - max_eth), token_reserve) # Throws if eth_sold > max_eth eth_refund: uint256(wei) = max_eth - as_wei_value(eth_sold, 'wei') if eth_refund > 0: send(buyer, eth_refund) assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, as_wei_value(eth_sold, 'wei'), tokens_bought) return as_wei_value(eth_sold, 'wei') # @notice Convert ETH to Tokens. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought Amount of tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH sold. @public @payable def ethToTokenSwapOutput(tokens_bought: uint256, deadline: timestamp) -> uint256(wei): return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought Amount of tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output Tokens. # @return Amount of ETH sold. @public @payable def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, recipient) @private def tokenToEthInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_sold > 0 and min_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth send(recipient, wei_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, wei_bought) return wei_bought # @notice Convert Tokens to ETH. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth Minimum ETH purchased. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH bought. @public def tokenToEthSwapInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp) -> uint256(wei): return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth Minimum ETH purchased. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @return Amount of ETH bought. @public def tokenToEthTransferInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, recipient) @private def tokenToEthOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens >= tokens_sold send(recipient, eth_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens to ETH. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens Maximum Tokens sold. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens sold. @public def tokenToEthSwapOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp) -> uint256: return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens Maximum Tokens sold. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @return Amount of Tokens sold. @public def tokenToEthTransferOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, recipient) @private def tokenToTokenInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert (deadline >= block.timestamp and tokens_sold > 0) and (min_tokens_bought > 0 and min_eth_bought > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) tokens_bought: uint256 = Exchange(exchange_addr).ethToTokenTransferInput(min_tokens_bought, deadline, recipient, value=wei_bought) log.EthPurchase(buyer, tokens_sold, wei_bought) return tokens_bought # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) @private def tokenToTokenOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth_sold > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS eth_bought: uint256(wei) = Exchange(exchange_addr).getEthToTokenOutputPrice(tokens_bought) token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens_sold >= tokens_sold and max_eth_sold >= eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) eth_sold: uint256(wei) = Exchange(exchange_addr).ethToTokenTransferOutput(tokens_bought, deadline, recipient, value=eth_bought) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Public price function for ETH to Token trades with an exact input. # @param eth_sold Amount of ETH sold. # @return Amount of Tokens that can be bought with input ETH. @public @constant def getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256: assert eth_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance), token_reserve) # @notice Public price function for ETH to Token trades with an exact output. # @param tokens_bought Amount of Tokens bought. # @return Amount of ETH needed to buy output Tokens. @public @constant def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): assert tokens_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance), token_reserve) return as_wei_value(eth_sold, 'wei') # @notice Public price function for Token to ETH trades with an exact input. # @param tokens_sold Amount of Tokens sold. # @return Amount of ETH that can be bought with input Tokens. @public @constant def getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei): assert tokens_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) return as_wei_value(eth_bought, 'wei') # @notice Public price function for Token to ETH trades with an exact output. # @param eth_bought Amount of output ETH. # @return Amount of Tokens needed to buy output ETH. @public @constant def getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256: assert eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # @return Address of Token that is sold on this exchange. @public @constant def tokenAddress() -> address: return self.token # @return Address of factory that created this exchange. @public @constant def factoryAddress() -> address(Factory): return self.factory # ERC20 compatibility for exchange liquidity modified from # https://github.com/ethereum/vyper/blob/master/examples/tokens/ERC20.vy @public @constant def balanceOf(_owner : address) -> uint256: return self.balances[_owner] @public def transfer(_to : address, _value : uint256) -> bool: self.balances[msg.sender] -= _value self.balances[_to] += _value log.Transfer(msg.sender, _to, _value) return True @public def transferFrom(_from : address, _to : address, _value : uint256) -> bool: self.balances[_from] -= _value self.balances[_to] += _value self.allowances[_from][msg.sender] -= _value log.Transfer(_from, _to, _value) return True @public def approve(_spender : address, _value : uint256) -> bool: self.allowances[msg.sender][_spender] = _value log.Approval(msg.sender, _spender, _value) return True @public @constant def allowance(_owner : address, _spender : address) -> uint256: return self.allowances[_owner][_spender]
File 5 of 7: FiatTokenV1
pragma solidity ^0.4.24; // File: contracts/Ownable.sol /** * Copyright CENTRE SECZ 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished to * do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity ^0.4.24; /** * @title Ownable * @dev The Ownable contract from https://github.com/zeppelinos/labs/blob/master/upgradeability_ownership/contracts/ownership/Ownable.sol * branch: master commit: 3887ab77b8adafba4a26ace002f3a684c1a3388b modified to: * 1) Add emit prefix to OwnershipTransferred event (7/13/18) * 2) Replace constructor with constructor syntax (7/13/18) * 3) consolidate OwnableStorage into this contract */ contract Ownable { // Owner of the contract address private _owner; /** * @dev Event to show ownership has been transferred * @param previousOwner representing the address of the previous owner * @param newOwner representing the address of the new owner */ event OwnershipTransferred(address previousOwner, address newOwner); /** * @dev The constructor sets the original owner of the contract to the sender account. */ constructor() public { setOwner(msg.sender); } /** * @dev Tells the address of the owner * @return the address of the owner */ function owner() public view returns (address) { return _owner; } /** * @dev Sets a new owner address */ function setOwner(address newOwner) internal { _owner = newOwner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner()); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0)); emit OwnershipTransferred(owner(), newOwner); setOwner(newOwner); } } // File: contracts/Blacklistable.sol /** * Copyright CENTRE SECZ 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished to * do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity ^0.4.24; /** * @title Blacklistable Token * @dev Allows accounts to be blacklisted by a "blacklister" role */ contract Blacklistable is Ownable { address public blacklister; mapping(address => bool) internal blacklisted; event Blacklisted(address indexed _account); event UnBlacklisted(address indexed _account); event BlacklisterChanged(address indexed newBlacklister); /** * @dev Throws if called by any account other than the blacklister */ modifier onlyBlacklister() { require(msg.sender == blacklister); _; } /** * @dev Throws if argument account is blacklisted * @param _account The address to check */ modifier notBlacklisted(address _account) { require(blacklisted[_account] == false); _; } /** * @dev Checks if account is blacklisted * @param _account The address to check */ function isBlacklisted(address _account) public view returns (bool) { return blacklisted[_account]; } /** * @dev Adds account to blacklist * @param _account The address to blacklist */ function blacklist(address _account) public onlyBlacklister { blacklisted[_account] = true; emit Blacklisted(_account); } /** * @dev Removes account from blacklist * @param _account The address to remove from the blacklist */ function unBlacklist(address _account) public onlyBlacklister { blacklisted[_account] = false; emit UnBlacklisted(_account); } function updateBlacklister(address _newBlacklister) public onlyOwner { require(_newBlacklister != address(0)); blacklister = _newBlacklister; emit BlacklisterChanged(blacklister); } } // File: contracts/Pausable.sol /** * Copyright CENTRE SECZ 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished to * do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity ^0.4.24; /** * @title Pausable * @dev Base contract which allows children to implement an emergency stop mechanism. * Based on openzeppelin tag v1.10.0 commit: feb665136c0dae9912e08397c1a21c4af3651ef3 * Modifications: * 1) Added pauser role, switched pause/unpause to be onlyPauser (6/14/2018) * 2) Removed whenNotPause/whenPaused from pause/unpause (6/14/2018) * 3) Removed whenPaused (6/14/2018) * 4) Switches ownable library to use zeppelinos (7/12/18) * 5) Remove constructor (7/13/18) */ contract Pausable is Ownable { event Pause(); event Unpause(); event PauserChanged(address indexed newAddress); address public pauser; bool public paused = false; /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!paused); _; } /** * @dev throws if called by any account other than the pauser */ modifier onlyPauser() { require(msg.sender == pauser); _; } /** * @dev called by the owner to pause, triggers stopped state */ function pause() onlyPauser public { paused = true; emit Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() onlyPauser public { paused = false; emit Unpause(); } /** * @dev update the pauser role */ function updatePauser(address _newPauser) onlyOwner public { require(_newPauser != address(0)); pauser = _newPauser; emit PauserChanged(pauser); } } // File: openzeppelin-solidity/contracts/math/SafeMath.sol /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting '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; } c = a * b; assert(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return a / b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; assert(c >= a); return c; } } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * See https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public view returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/FiatTokenV1.sol /** * Copyright CENTRE SECZ 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is furnished to * do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ pragma solidity ^0.4.24; /** * @title FiatToken * @dev ERC20 Token backed by fiat reserves */ contract FiatTokenV1 is Ownable, ERC20, Pausable, Blacklistable { using SafeMath for uint256; string public name; string public symbol; uint8 public decimals; string public currency; address public masterMinter; bool internal initialized; mapping(address => uint256) internal balances; mapping(address => mapping(address => uint256)) internal allowed; uint256 internal totalSupply_ = 0; mapping(address => bool) internal minters; mapping(address => uint256) internal minterAllowed; event Mint(address indexed minter, address indexed to, uint256 amount); event Burn(address indexed burner, uint256 amount); event MinterConfigured(address indexed minter, uint256 minterAllowedAmount); event MinterRemoved(address indexed oldMinter); event MasterMinterChanged(address indexed newMasterMinter); function initialize( string _name, string _symbol, string _currency, uint8 _decimals, address _masterMinter, address _pauser, address _blacklister, address _owner ) public { require(!initialized); require(_masterMinter != address(0)); require(_pauser != address(0)); require(_blacklister != address(0)); require(_owner != address(0)); name = _name; symbol = _symbol; currency = _currency; decimals = _decimals; masterMinter = _masterMinter; pauser = _pauser; blacklister = _blacklister; setOwner(_owner); initialized = true; } /** * @dev Throws if called by any account other than a minter */ modifier onlyMinters() { require(minters[msg.sender] == true); _; } /** * @dev Function to mint tokens * @param _to The address that will receive the minted tokens. * @param _amount The amount of tokens to mint. Must be less than or equal to the minterAllowance of the caller. * @return A boolean that indicates if the operation was successful. */ function mint(address _to, uint256 _amount) whenNotPaused onlyMinters notBlacklisted(msg.sender) notBlacklisted(_to) public returns (bool) { require(_to != address(0)); require(_amount > 0); uint256 mintingAllowedAmount = minterAllowed[msg.sender]; require(_amount <= mintingAllowedAmount); totalSupply_ = totalSupply_.add(_amount); balances[_to] = balances[_to].add(_amount); minterAllowed[msg.sender] = mintingAllowedAmount.sub(_amount); emit Mint(msg.sender, _to, _amount); emit Transfer(0x0, _to, _amount); return true; } /** * @dev Throws if called by any account other than the masterMinter */ modifier onlyMasterMinter() { require(msg.sender == masterMinter); _; } /** * @dev Get minter allowance for an account * @param minter The address of the minter */ function minterAllowance(address minter) public view returns (uint256) { return minterAllowed[minter]; } /** * @dev Checks if account is a minter * @param account The address to check */ function isMinter(address account) public view returns (bool) { return minters[account]; } /** * @dev Get allowed amount for an account * @param owner address The account owner * @param spender address The account spender */ function allowance(address owner, address spender) public view returns (uint256) { return allowed[owner][spender]; } /** * @dev Get totalSupply of token */ function totalSupply() public view returns (uint256) { return totalSupply_; } /** * @dev Get token balance of an account * @param account address The account */ function balanceOf(address account) public view returns (uint256) { return balances[account]; } /** * @dev Adds blacklisted check to approve * @return True if the operation was successful. */ function approve(address _spender, uint256 _value) whenNotPaused notBlacklisted(msg.sender) notBlacklisted(_spender) public returns (bool) { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } /** * @dev Transfer tokens from one address to another. * @param _from address The address which you want to send tokens from * @param _to address The address which you want to transfer to * @param _value uint256 the amount of tokens to be transferred * @return bool success */ function transferFrom(address _from, address _to, uint256 _value) whenNotPaused notBlacklisted(_to) notBlacklisted(msg.sender) notBlacklisted(_from) public returns (bool) { require(_to != address(0)); require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); emit Transfer(_from, _to, _value); return true; } /** * @dev transfer token for a specified address * @param _to The address to transfer to. * @param _value The amount to be transferred. * @return bool success */ function transfer(address _to, uint256 _value) whenNotPaused notBlacklisted(msg.sender) notBlacklisted(_to) public returns (bool) { require(_to != address(0)); require(_value <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender].sub(_value); balances[_to] = balances[_to].add(_value); emit Transfer(msg.sender, _to, _value); return true; } /** * @dev Function to add/update a new minter * @param minter The address of the minter * @param minterAllowedAmount The minting amount allowed for the minter * @return True if the operation was successful. */ function configureMinter(address minter, uint256 minterAllowedAmount) whenNotPaused onlyMasterMinter public returns (bool) { minters[minter] = true; minterAllowed[minter] = minterAllowedAmount; emit MinterConfigured(minter, minterAllowedAmount); return true; } /** * @dev Function to remove a minter * @param minter The address of the minter to remove * @return True if the operation was successful. */ function removeMinter(address minter) onlyMasterMinter public returns (bool) { minters[minter] = false; minterAllowed[minter] = 0; emit MinterRemoved(minter); return true; } /** * @dev allows a minter to burn some of its own tokens * Validates that caller is a minter and that sender is not blacklisted * amount is less than or equal to the minter's account balance * @param _amount uint256 the amount of tokens to be burned */ function burn(uint256 _amount) whenNotPaused onlyMinters notBlacklisted(msg.sender) public { uint256 balance = balances[msg.sender]; require(_amount > 0); require(balance >= _amount); totalSupply_ = totalSupply_.sub(_amount); balances[msg.sender] = balance.sub(_amount); emit Burn(msg.sender, _amount); emit Transfer(msg.sender, address(0), _amount); } function updateMasterMinter(address _newMasterMinter) onlyOwner public { require(_newMasterMinter != address(0)); masterMinter = _newMasterMinter; emit MasterMinterChanged(masterMinter); } }
File 6 of 7: Vyper_contract
contract Exchange(): def setup(token_addr: address): modifying NewExchange: event({token: indexed(address), exchange: indexed(address)}) exchangeTemplate: public(address) tokenCount: public(uint256) token_to_exchange: address[address] exchange_to_token: address[address] id_to_token: address[uint256] @public def initializeFactory(template: address): assert self.exchangeTemplate == ZERO_ADDRESS assert template != ZERO_ADDRESS self.exchangeTemplate = template @public def createExchange(token: address) -> address: assert token != ZERO_ADDRESS assert self.exchangeTemplate != ZERO_ADDRESS assert self.token_to_exchange[token] == ZERO_ADDRESS exchange: address = create_with_code_of(self.exchangeTemplate) Exchange(exchange).setup(token) self.token_to_exchange[token] = exchange self.exchange_to_token[exchange] = token token_id: uint256 = self.tokenCount + 1 self.tokenCount = token_id self.id_to_token[token_id] = token log.NewExchange(token, exchange) return exchange @public @constant def getExchange(token: address) -> address: return self.token_to_exchange[token] @public @constant def getToken(exchange: address) -> address: return self.exchange_to_token[exchange] @public @constant def getTokenWithId(token_id: uint256) -> address: return self.id_to_token[token_id]
File 7 of 7: Vyper_contract
# @title Uniswap Exchange Interface V1 # @notice Source code found at https://github.com/uniswap # @notice Use at your own risk contract Factory(): def getExchange(token_addr: address) -> address: constant contract Exchange(): def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): constant def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: modifying def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): modifying TokenPurchase: event({buyer: indexed(address), eth_sold: indexed(uint256(wei)), tokens_bought: indexed(uint256)}) EthPurchase: event({buyer: indexed(address), tokens_sold: indexed(uint256), eth_bought: indexed(uint256(wei))}) AddLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) RemoveLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)}) Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256}) Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256}) name: public(bytes32) # Uniswap V1 symbol: public(bytes32) # UNI-V1 decimals: public(uint256) # 18 totalSupply: public(uint256) # total number of UNI in existence balances: uint256[address] # UNI balance of an address allowances: (uint256[address])[address] # UNI allowance of one address on another token: address(ERC20) # address of the ERC20 token traded on this contract factory: Factory # interface for the factory that created this contract # @dev This function acts as a contract constructor which is not currently supported in contracts deployed # using create_with_code_of(). It is called once by the factory during contract creation. @public def setup(token_addr: address): assert (self.factory == ZERO_ADDRESS and self.token == ZERO_ADDRESS) and token_addr != ZERO_ADDRESS self.factory = msg.sender self.token = token_addr self.name = 0x556e697377617020563100000000000000000000000000000000000000000000 self.symbol = 0x554e492d56310000000000000000000000000000000000000000000000000000 self.decimals = 18 # @notice Deposit ETH and Tokens (self.token) at current ratio to mint UNI tokens. # @dev min_liquidity does nothing when total UNI supply is 0. # @param min_liquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0. # @param max_tokens Maximum number of tokens deposited. Deposits max amount if total UNI supply is 0. # @param deadline Time after which this transaction can no longer be executed. # @return The amount of UNI minted. @public @payable def addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256: assert deadline > block.timestamp and (max_tokens > 0 and msg.value > 0) total_liquidity: uint256 = self.totalSupply if total_liquidity > 0: assert min_liquidity > 0 eth_reserve: uint256(wei) = self.balance - msg.value token_reserve: uint256 = self.token.balanceOf(self) token_amount: uint256 = msg.value * token_reserve / eth_reserve + 1 liquidity_minted: uint256 = msg.value * total_liquidity / eth_reserve assert max_tokens >= token_amount and liquidity_minted >= min_liquidity self.balances[msg.sender] += liquidity_minted self.totalSupply = total_liquidity + liquidity_minted assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, liquidity_minted) return liquidity_minted else: assert (self.factory != ZERO_ADDRESS and self.token != ZERO_ADDRESS) and msg.value >= 1000000000 assert self.factory.getExchange(self.token) == self token_amount: uint256 = max_tokens initial_liquidity: uint256 = as_unitless_number(self.balance) self.totalSupply = initial_liquidity self.balances[msg.sender] = initial_liquidity assert self.token.transferFrom(msg.sender, self, token_amount) log.AddLiquidity(msg.sender, msg.value, token_amount) log.Transfer(ZERO_ADDRESS, msg.sender, initial_liquidity) return initial_liquidity # @dev Burn UNI tokens to withdraw ETH and Tokens at current ratio. # @param amount Amount of UNI burned. # @param min_eth Minimum ETH withdrawn. # @param min_tokens Minimum Tokens withdrawn. # @param deadline Time after which this transaction can no longer be executed. # @return The amount of ETH and Tokens withdrawn. @public def removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256): assert (amount > 0 and deadline > block.timestamp) and (min_eth > 0 and min_tokens > 0) total_liquidity: uint256 = self.totalSupply assert total_liquidity > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_amount: uint256(wei) = amount * self.balance / total_liquidity token_amount: uint256 = amount * token_reserve / total_liquidity assert eth_amount >= min_eth and token_amount >= min_tokens self.balances[msg.sender] -= amount self.totalSupply = total_liquidity - amount send(msg.sender, eth_amount) assert self.token.transfer(msg.sender, token_amount) log.RemoveLiquidity(msg.sender, eth_amount, token_amount) log.Transfer(msg.sender, ZERO_ADDRESS, amount) return eth_amount, token_amount # @dev Pricing function for converting between ETH and Tokens. # @param input_amount Amount of ETH or Tokens being sold. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens bought. @private @constant def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 input_amount_with_fee: uint256 = input_amount * 997 numerator: uint256 = input_amount_with_fee * output_reserve denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee return numerator / denominator # @dev Pricing function for converting between ETH and Tokens. # @param output_amount Amount of ETH or Tokens being bought. # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves. # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves. # @return Amount of ETH or Tokens sold. @private @constant def getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256: assert input_reserve > 0 and output_reserve > 0 numerator: uint256 = input_reserve * output_amount * 1000 denominator: uint256 = (output_reserve - output_amount) * 997 return numerator / denominator + 1 @private def ethToTokenInput(eth_sold: uint256(wei), min_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and (eth_sold > 0 and min_tokens > 0) token_reserve: uint256 = self.token.balanceOf(self) tokens_bought: uint256 = self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance - eth_sold), token_reserve) assert tokens_bought >= min_tokens assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, eth_sold, tokens_bought) return tokens_bought # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value). # @dev User cannot specify minimum output or deadline. @public @payable def __default__(): self.ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender) # @notice Convert ETH to Tokens. # @dev User specifies exact input (msg.value) and minimum output. # @param min_tokens Minimum Tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens bought. @public @payable def ethToTokenSwapInput(min_tokens: uint256, deadline: timestamp) -> uint256: return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies exact input (msg.value) and minimum output # @param min_tokens Minimum Tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output Tokens. # @return Amount of Tokens bought. @public @payable def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, recipient) @private def ethToTokenOutput(tokens_bought: uint256, max_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance - max_eth), token_reserve) # Throws if eth_sold > max_eth eth_refund: uint256(wei) = max_eth - as_wei_value(eth_sold, 'wei') if eth_refund > 0: send(buyer, eth_refund) assert self.token.transfer(recipient, tokens_bought) log.TokenPurchase(buyer, as_wei_value(eth_sold, 'wei'), tokens_bought) return as_wei_value(eth_sold, 'wei') # @notice Convert ETH to Tokens. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought Amount of tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH sold. @public @payable def ethToTokenSwapOutput(tokens_bought: uint256, deadline: timestamp) -> uint256(wei): return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, msg.sender) # @notice Convert ETH to Tokens and transfers Tokens to recipient. # @dev User specifies maximum input (msg.value) and exact output. # @param tokens_bought Amount of tokens bought. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output Tokens. # @return Amount of ETH sold. @public @payable def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, recipient) @private def tokenToEthInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei): assert deadline >= block.timestamp and (tokens_sold > 0 and min_eth > 0) token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth send(recipient, wei_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, wei_bought) return wei_bought # @notice Convert Tokens to ETH. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth Minimum ETH purchased. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of ETH bought. @public def tokenToEthSwapInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp) -> uint256(wei): return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_eth Minimum ETH purchased. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @return Amount of ETH bought. @public def tokenToEthTransferInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, recipient: address) -> uint256(wei): assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, recipient) @private def tokenToEthOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256: assert deadline >= block.timestamp and eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens >= tokens_sold send(recipient, eth_bought) assert self.token.transferFrom(buyer, self, tokens_sold) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens to ETH. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens Maximum Tokens sold. # @param deadline Time after which this transaction can no longer be executed. # @return Amount of Tokens sold. @public def tokenToEthSwapOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp) -> uint256: return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, msg.sender) # @notice Convert Tokens to ETH and transfers ETH to recipient. # @dev User specifies maximum input and exact output. # @param eth_bought Amount of ETH purchased. # @param max_tokens Maximum Tokens sold. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @return Amount of Tokens sold. @public def tokenToEthTransferOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: assert recipient != self and recipient != ZERO_ADDRESS return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, recipient) @private def tokenToTokenInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert (deadline >= block.timestamp and tokens_sold > 0) and (min_tokens_bought > 0 and min_eth_bought > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei') assert wei_bought >= min_eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) tokens_bought: uint256 = Exchange(exchange_addr).ethToTokenTransferInput(min_tokens_bought, deadline, recipient, value=wei_bought) log.EthPurchase(buyer, tokens_sold, wei_bought) return tokens_bought # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (token_addr) bought. @public def tokenToTokenTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) @private def tokenToTokenOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256: assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth_sold > 0) assert exchange_addr != self and exchange_addr != ZERO_ADDRESS eth_bought: uint256(wei) = Exchange(exchange_addr).getEthToTokenOutputPrice(tokens_bought) token_reserve: uint256 = self.token.balanceOf(self) tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # tokens sold is always > 0 assert max_tokens_sold >= tokens_sold and max_eth_sold >= eth_bought assert self.token.transferFrom(buyer, self, tokens_sold) eth_sold: uint256(wei) = Exchange(exchange_addr).ethToTokenTransferOutput(tokens_bought, deadline, recipient, value=eth_bought) log.EthPurchase(buyer, tokens_sold, eth_bought) return tokens_sold # @notice Convert Tokens (self.token) to Tokens (token_addr). # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers # Tokens (token_addr) to recipient. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToTokenTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256: exchange_addr: address = self.factory.getExchange(token_addr) return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies exact input and minimum output. # @param tokens_sold Amount of Tokens sold. # @param min_tokens_bought Minimum Tokens (token_addr) purchased. # @param min_eth_bought Minimum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (exchange_addr.token) bought. @public def tokenToExchangeTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token). # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param exchange_addr The address of the exchange for the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256: return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr) # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers # Tokens (exchange_addr.token) to recipient. # @dev Allows trades through contracts that were not deployed from the same factory. # @dev User specifies maximum input and exact output. # @param tokens_bought Amount of Tokens (token_addr) bought. # @param max_tokens_sold Maximum Tokens (self.token) sold. # @param max_eth_sold Maximum ETH purchased as intermediary. # @param deadline Time after which this transaction can no longer be executed. # @param recipient The address that receives output ETH. # @param token_addr The address of the token being purchased. # @return Amount of Tokens (self.token) sold. @public def tokenToExchangeTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256: assert recipient != self return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr) # @notice Public price function for ETH to Token trades with an exact input. # @param eth_sold Amount of ETH sold. # @return Amount of Tokens that can be bought with input ETH. @public @constant def getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256: assert eth_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance), token_reserve) # @notice Public price function for ETH to Token trades with an exact output. # @param tokens_bought Amount of Tokens bought. # @return Amount of ETH needed to buy output Tokens. @public @constant def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): assert tokens_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance), token_reserve) return as_wei_value(eth_sold, 'wei') # @notice Public price function for Token to ETH trades with an exact input. # @param tokens_sold Amount of Tokens sold. # @return Amount of ETH that can be bought with input Tokens. @public @constant def getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei): assert tokens_sold > 0 token_reserve: uint256 = self.token.balanceOf(self) eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance)) return as_wei_value(eth_bought, 'wei') # @notice Public price function for Token to ETH trades with an exact output. # @param eth_bought Amount of output ETH. # @return Amount of Tokens needed to buy output ETH. @public @constant def getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256: assert eth_bought > 0 token_reserve: uint256 = self.token.balanceOf(self) return self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance)) # @return Address of Token that is sold on this exchange. @public @constant def tokenAddress() -> address: return self.token # @return Address of factory that created this exchange. @public @constant def factoryAddress() -> address(Factory): return self.factory # ERC20 compatibility for exchange liquidity modified from # https://github.com/ethereum/vyper/blob/master/examples/tokens/ERC20.vy @public @constant def balanceOf(_owner : address) -> uint256: return self.balances[_owner] @public def transfer(_to : address, _value : uint256) -> bool: self.balances[msg.sender] -= _value self.balances[_to] += _value log.Transfer(msg.sender, _to, _value) return True @public def transferFrom(_from : address, _to : address, _value : uint256) -> bool: self.balances[_from] -= _value self.balances[_to] += _value self.allowances[_from][msg.sender] -= _value log.Transfer(_from, _to, _value) return True @public def approve(_spender : address, _value : uint256) -> bool: self.allowances[msg.sender][_spender] = _value log.Approval(msg.sender, _spender, _value) return True @public @constant def allowance(_owner : address, _spender : address) -> uint256: return self.allowances[_owner][_spender]