-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Otoken: Burn and Mint #31
Merged
Merged
Changes from 26 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
cc5cdc1
Rearrange oz folders and init commit on oToken.sol
antoncoding 0def9c7
Merge branch 'master' into otoken
antoncoding 1afd524
Add descriptions for function parameters
antoncoding d81de7c
Add layout for otoken tests
antoncoding 8a270dc
Remove ERC20 operation from this branch
antoncoding e2b37bb
Add BokkyPooBahsDateTimeLibrary and convert timestamp to date string.
antoncoding efdefeb
Add tests for Otoken.sol.
antoncoding 1416525
Merge branch 'master' into otoken-init
antoncoding c85a46f
Merge with master
antoncoding 80b1fc3
Remove unused function in DateTimeLibrary.
antoncoding d8547fe
Add comments, test different name/symbol strings
antoncoding 0f012d0
Merge with interface change
antoncoding 115b2ef
Add non-eth asset test
antoncoding 59961e7
Rearrange test orders and add expiry test for now + 3000 years
antoncoding f35feda
Add 0 expiry and max uint256 expiry test
antoncoding 643de3c
Use new name and symbol
antoncoding d3ece87
Remove mapping, refactor optino type and month string getters.
antoncoding 3aee134
Remove args for getNameAndSymbol function
antoncoding 59e88a0
Make test coverage 100%
antoncoding b7857a5
Add test for init twice with different parameters
antoncoding 85dca18
Add mintOtoken and burnOtoken functions and tests
antoncoding 1bcec75
Add comments
antoncoding bca1d5a
Rearrange function orders
antoncoding 526805c
Simplify otoken test syntax.
antoncoding c3bf565
Add more comments
antoncoding d21b751
Merge with new test file.
antoncoding 967b64b
Fix typos
antoncoding c33204f
Merge branch 'master' into otoken-erc20
antoncoding 7096c07
Merge with master
antoncoding File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,242 @@ | ||
/** | ||
* SPDX-License-Identifier: UNLICENSED | ||
*/ | ||
pragma solidity 0.6.10; | ||
/* SPDX-License-Identifier: UNLICENSED */ | ||
pragma solidity =0.6.10; | ||
|
||
import {ERC20Initializable} from "./packages/oz/upgradeability/ERC20Initializable.sol"; | ||
import {SafeMath} from "./packages/oz/SafeMath.sol"; | ||
import {Strings} from "./packages/oz/Strings.sol"; | ||
import {BokkyPooBahsDateTimeLibrary} from "./packages/BokkyPooBahsDateTimeLibrary.sol"; | ||
import {AddressBookInterface} from "./interfaces/AddressBookInterface.sol"; | ||
|
||
/** | ||
* | ||
* @title Otoken | ||
* @author Opyn | ||
* @notice Otoken is the ERC20 token for an option. | ||
* @dev The Otoken inherits ERC20Initializable because we need to use the init instead of constructor. | ||
*/ | ||
// solhint-disable-next-line no-empty-blocks | ||
contract Otoken { | ||
contract Otoken is ERC20Initializable { | ||
using SafeMath for uint256; | ||
|
||
/// @notice address of the addressBook module | ||
address public addressBook; | ||
|
||
/// @notice asset that the option references | ||
address public underlyingAsset; | ||
|
||
/// @notice asset that the strike price is denominated in | ||
address public strikeAsset; | ||
|
||
/// @notice asset that is held as collateral against short/written options | ||
address public collateralAsset; | ||
|
||
/// @notice strike price with decimals = 18 | ||
uint256 public strikePrice; | ||
|
||
/// @notice time of the option represented by unix timestamp | ||
uint256 public expiry; | ||
|
||
/// @notice is this a put option, if not it is a call | ||
bool public isPut; | ||
|
||
uint256 private constant STRIKE_PRICE_DIGITS = 1e18; | ||
|
||
constructor(address _addressBook) public { | ||
addressBook = _addressBook; | ||
} | ||
|
||
/** | ||
* @notice initialize the otoken. | ||
* @param _underlyingAsset asset that the option references | ||
* @param _strikeAsset asset that the strike price is denominated in | ||
* @param _collateralAsset asset that is held as collateral against short/written options | ||
* @param _strikePrice strike price with decimals = 18 | ||
* @param _expiry time of the option represented by unix timestamp | ||
* @param _isPut is this a put option, if not it is a call | ||
*/ | ||
function init( | ||
address _underlyingAsset, | ||
address _strikeAsset, | ||
address _collateralAsset, | ||
uint256 _strikePrice, | ||
uint256 _expiry, | ||
bool _isPut | ||
) external initializer { | ||
underlyingAsset = _underlyingAsset; | ||
strikeAsset = _strikeAsset; | ||
collateralAsset = _collateralAsset; | ||
strikePrice = _strikePrice; | ||
expiry = _expiry; | ||
isPut = _isPut; | ||
(string memory name, string memory symbol) = _getNameAndSymbol(); | ||
__ERC20_init_unchained(name, symbol); | ||
} | ||
|
||
/** | ||
* @notice Mint oToken for an account. | ||
* @dev this is a Controller only method. Access control is taken care of by _beforeTokenTransfer hook. | ||
* @param account the account to mint token to | ||
* @param amount the amount to mint | ||
*/ | ||
function mintOtoken(address account, uint256 amount) external { | ||
_mint(account, amount); | ||
} | ||
|
||
/** | ||
* @notice Burn oToken from an account. | ||
* @dev this is a Controller only method. Access control is taken care of by _beforeTokenTransfer hook. | ||
* @param account the account to burn token from | ||
* @param amount the amount to burn | ||
*/ | ||
function burnOtoken(address account, uint256 amount) external { | ||
_burn(account, amount); | ||
} | ||
|
||
/** | ||
* @notice generate name and symbol for an option | ||
* @return name ETHUSDC 05-September-2020 200 Put USDC Collateral | ||
* @return symbol oETHUSDC-05SEP20-200P | ||
*/ | ||
function _getNameAndSymbol() internal view returns (string memory name, string memory symbol) { | ||
string memory underlying = _getTokenSymbol(underlyingAsset); | ||
string memory strike = _getTokenSymbol(strikeAsset); | ||
string memory collateral = _getTokenSymbol(collateralAsset); | ||
uint256 displayedStrikePrice = strikePrice.div(STRIKE_PRICE_DIGITS); | ||
// convert expiry to readable string | ||
(uint256 year, uint256 month, uint256 day) = BokkyPooBahsDateTimeLibrary.timestampToDate(expiry); | ||
|
||
// Get option type string | ||
(string memory typeSymbol, string memory typeFull) = _getOptionType(isPut); | ||
|
||
(string memory monthSymbol, string memory monthFull) = _getMonth(month); | ||
|
||
// concat name string: ETHUSDC 05-September-2020 200 Put USDC Collateral | ||
name = string( | ||
abi.encodePacked( | ||
underlying, | ||
strike, | ||
" ", | ||
_uintTo2Chars(day), | ||
"-", | ||
monthFull, | ||
"-", | ||
Strings.toString(year), | ||
" ", | ||
Strings.toString(displayedStrikePrice), | ||
typeFull, | ||
" ", | ||
collateral, | ||
" Collateral" | ||
) | ||
); | ||
|
||
// concat symbol string: oETHUSDC-05SEP20-200P | ||
symbol = string( | ||
abi.encodePacked( | ||
"o", | ||
underlying, | ||
strike, | ||
"-", | ||
_uintTo2Chars(day), | ||
monthSymbol, | ||
_uintTo2Chars(year), | ||
"-", | ||
Strings.toString(displayedStrikePrice), | ||
typeSymbol | ||
) | ||
); | ||
} | ||
|
||
/** | ||
* @dev get token symbol | ||
* @param token the ERC20 token address | ||
*/ | ||
function _getTokenSymbol(address token) internal view returns (string memory) { | ||
if (token == address(0)) return "ETH"; | ||
else return ERC20Initializable(token).symbol(); | ||
} | ||
|
||
/** | ||
* @dev Internal function to get the number with 2 characters. | ||
* @return The 2 characters for the number. | ||
*/ | ||
function _uintTo2Chars(uint256 number) internal pure returns (string memory) { | ||
string memory str = Strings.toString(number); | ||
if (number > 99) return Strings.toString(number % 100); | ||
if (number < 10) { | ||
return string(abi.encodePacked("0", str)); | ||
} else { | ||
return str; | ||
} | ||
} | ||
|
||
/** | ||
* @dev return string of optino type | ||
antoncoding marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @return symbol P or C | ||
* @return full Put or Call | ||
*/ | ||
function _getOptionType(bool _isPut) internal pure returns (string memory symbol, string memory full) { | ||
if (_isPut) { | ||
return ("P", "Put"); | ||
} else { | ||
return ("C", "Call"); | ||
} | ||
} | ||
|
||
/** | ||
* @dev return string of month. | ||
* @return symbol SEP, DEC ...etc | ||
* @return full September, December ...etc | ||
*/ | ||
function _getMonth(uint256 _month) internal pure returns (string memory symbol, string memory full) { | ||
if (_month == 1) { | ||
return ("JAN", "January"); | ||
} else if (_month == 2) { | ||
return ("FEB", "February"); | ||
} else if (_month == 3) { | ||
return ("MAR", "March"); | ||
} else if (_month == 4) { | ||
return ("APR", "April"); | ||
} else if (_month == 5) { | ||
return ("MAY", "May"); | ||
} else if (_month == 6) { | ||
return ("JUN", "June"); | ||
} else if (_month == 7) { | ||
return ("JUL", "July"); | ||
} else if (_month == 8) { | ||
return ("AUG", "August"); | ||
} else if (_month == 9) { | ||
return ("SEP", "September"); | ||
} else if (_month == 10) { | ||
return ("OCT", "October"); | ||
} else if (_month == 11) { | ||
return ("NOV", "November"); | ||
} else { | ||
return ("DEC", "December"); | ||
} | ||
} | ||
|
||
/** | ||
* @dev this function overrides the _beforeTokenTransfer hook in ERC20Initializable.sol. | ||
* If the operation is mint or burn, requires msg.sender to be the controller. | ||
* @dev the functino signature is the same as _beforeTokenTransfer defined in ERC20Initializable.sol. | ||
antoncoding marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @param from from address | ||
* @param to to address | ||
* @param amount amount to transfer | ||
*/ | ||
function _beforeTokenTransfer( | ||
address from, | ||
address to, | ||
uint256 amount | ||
) internal override { | ||
if (from == address(0)) { | ||
require( | ||
msg.sender == AddressBookInterface(addressBook).getController(), | ||
"Otoken: Only Controller can mint Otokens." | ||
); | ||
} else if (to == address(0)) { | ||
require( | ||
msg.sender == AddressBookInterface(addressBook).getController(), | ||
"Otoken: Only Controller can burn Otokens." | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// SPDX-License-Identifier: MIT | ||
// solhint-disable | ||
pragma solidity ^0.6.0; | ||
|
||
// ---------------------------------------------------------------------------- | ||
// BokkyPooBah's DateTime Library v1.01 | ||
// | ||
// A gas-efficient Solidity date and time library | ||
// | ||
// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary | ||
// | ||
// Tested date range 1970/01/01 to 2345/12/31 | ||
// | ||
// Conventions: | ||
// Unit | Range | Notes | ||
// :-------- |:-------------:|:----- | ||
// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC | ||
// year | 1970 ... 2345 | | ||
// month | 1 ... 12 | | ||
// day | 1 ... 31 | | ||
// hour | 0 ... 23 | | ||
// minute | 0 ... 59 | | ||
// second | 0 ... 59 | | ||
// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday | ||
// | ||
// | ||
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. | ||
// ---------------------------------------------------------------------------- | ||
|
||
library BokkyPooBahsDateTimeLibrary { | ||
uint256 constant SECONDS_PER_DAY = 24 * 60 * 60; | ||
int256 constant OFFSET19700101 = 2440588; | ||
|
||
// ------------------------------------------------------------------------ | ||
// Calculate year/month/day from the number of days since 1970/01/01 using | ||
// the date conversion algorithm from | ||
// http://aa.usno.navy.mil/faq/docs/JD_Formula.php | ||
// and adding the offset 2440588 so that 1970/01/01 is day 0 | ||
// | ||
// int L = days + 68569 + offset | ||
// int N = 4 * L / 146097 | ||
// L = L - (146097 * N + 3) / 4 | ||
// year = 4000 * (L + 1) / 1461001 | ||
// L = L - 1461 * year / 4 + 31 | ||
// month = 80 * L / 2447 | ||
// dd = L - 2447 * month / 80 | ||
// L = month / 11 | ||
// month = month + 2 - 12 * L | ||
// year = 100 * (N - 49) + year + L | ||
// ------------------------------------------------------------------------ | ||
function _daysToDate(uint256 _days) | ||
internal | ||
pure | ||
returns ( | ||
uint256 year, | ||
uint256 month, | ||
uint256 day | ||
) | ||
{ | ||
int256 __days = int256(_days); | ||
|
||
int256 L = __days + 68569 + OFFSET19700101; | ||
int256 N = (4 * L) / 146097; | ||
L = L - (146097 * N + 3) / 4; | ||
int256 _year = (4000 * (L + 1)) / 1461001; | ||
L = L - (1461 * _year) / 4 + 31; | ||
int256 _month = (80 * L) / 2447; | ||
int256 _day = L - (2447 * _month) / 80; | ||
L = _month / 11; | ||
_month = _month + 2 - 12 * L; | ||
_year = 100 * (N - 49) + _year + L; | ||
|
||
year = uint256(_year); | ||
month = uint256(_month); | ||
day = uint256(_day); | ||
} | ||
|
||
function timestampToDate(uint256 timestamp) | ||
internal | ||
pure | ||
returns ( | ||
uint256 year, | ||
uint256 month, | ||
uint256 day | ||
) | ||
{ | ||
(year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where are the decimals set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is set in the
__ERC20_init_unchained
function