Blockwell

CBOND

About

Stats

Public Functions 47
Event Types 7
Code Size 101,102 bytes

Library Use

Uses SafeMath for uint256.
Uses Strings for uint256.
Uses AddressStrings for address.

Events (7) keyboard_arrow_up

Approval Event

Parameters help
owner
address help
approved
address help
tokenId
uint256 help

ApprovalForAll Event

Parameters help
owner
address help
operator
address help
approved
bool help

Created Event

Parameters help
token
address help
syncAmount
uint256 help
tokenAmount
uint256 help
syncPrice
uint256 help
tokenPrice
uint256 help
tokenId
uint256 help

DivsPaid Event

Parameters help
token
address help
syncReturned
uint256 help
tokenId
uint256 help

Matured Event

Parameters help
token
address help
syncReturned
uint256 help
tokenAmount
uint256 help
tokenId
uint256 help

OwnershipTransferred Event

Parameters help
previousOwner
address help
newOwner
address help

Transfer Event

Parameters help
from
address help
to
address help
tokenId
uint256 help

PERCENTAGE_PRECISION Constant

uint256 help
10000

INCENTIVE_MAX_PERCENT Constant

uint256 help
220

MAX_SYNC_GLOBAL Constant

uint256 help
100000 * UNKNOWN VALUE

QUARTER_LENGTH Constant

uint256 help
90 days

BASE_INTEREST_RATE_START Constant

uint256 help
220

MINIMUM_BASE_INTEREST_RATE Constant

uint256 help
10

MAXIMUM_BASE_INTEREST_RATE Constant

uint256 help
4500

_ERC721_RECEIVED Constant

bytes4 help
0x150b7a02

_INTERFACE_ID_ERC721 Constant

bytes4 help
0x80ac58cd

_INTERFACE_ID_ERC721_METADATA Constant

bytes4 help
0x5b5e139f

_INTERFACE_ID_ERC721_ENUMERABLE Constant

bytes4 help
0x780e9d63

_INTERFACE_ID_ERC165 Constant

bytes4 help
0x01ffc9a7

totalCBONDS Variable

uint256 help

totalQuarterlyCBONDS Variable

uint256 help

totalCBONDSCashedout Variable

uint256 help

totalSYNCLocked Variable

uint256 help

STARTING_TIME Variable

uint256 help

YEAR_LENGTH Variable

uint256 help

RISK_FACTOR Variable

uint256 help

lastDaySyncSupplyUpdated Variable

uint256 help

currentDaySyncSupplyUpdated Variable

uint256 help

_currentTokenId Variable

uint256 help

syncMinimum Variable

uint256 help

luckyEnabled Variable

bool help

priceChecker Variable

address help

totalLiquidityLockedByPair Variable

mapping(address => uint256) help

lAddrById Variable

mapping(uint256 => address) help

lTokenPriceById Variable

mapping(uint256 => uint256) help

lTokenAmountById Variable

mapping(uint256 => uint256) help

syncPriceById Variable

mapping(uint256 => uint256) help

syncAmountById Variable

mapping(uint256 => uint256) help

syncInterestById Variable

mapping(uint256 => uint256) help

syncRewardedOnMaturity Variable

mapping(uint256 => uint256) help

timestampById Variable

mapping(uint256 => uint256) help

gradualDivsById Variable

mapping(uint256 => bool) help

lastDivsCashoutById Variable

mapping(uint256 => uint256) help

totalDivsCashoutById Variable

mapping(uint256 => uint256) help

termLengthById Variable

mapping(uint256 => uint256) help

INDEX_BY_DURATION Variable

mapping(uint256 => uint256) help

cbondsHeldByUserCursor Variable

mapping(address => uint256) help

lastDayTokenSupplyUpdated Variable

mapping(address => uint256) help

currentDayTokenSupplyUpdated Variable

mapping(address => uint256) help

syncSupplyByDay Variable

mapping(uint256 => uint256) help

interestRateByDay Variable

mapping(uint256 => uint256) help

cbondsMaturingByDay Variable

mapping(uint256 => uint256) help

tokenAccepted Variable

mapping(address => bool) help

LUCKY_EXTRAS Variable

uint256[] help
Internal Variable

TERM_DURATIONS Variable

uint256[] help
Internal Variable

DURATION_MODIFIERS Variable

uint256[] help
Internal Variable

DURATION_CALC_LOOPS Variable

uint256[] help
Internal Variable

cbondsHeldByUser Variable

mapping(address => mapping(uint256 => uint256)) help
Internal Variable

liqTokenTotalsByDay Variable

mapping(address => mapping(uint256 => uint256)) help
Internal Variable

syncToken Variable

Sync help
Internal Variable

_holderTokens Variable

mapping(address => EnumerableSet.UintSet) help
Internal Variable

_tokenOwners Variable

EnumerableMap.UintToAddressMap help
Internal Variable

_tokenApprovals Variable

mapping(uint256 => address) help
Internal Variable

_operatorApprovals Variable

mapping(address => mapping(address => bool)) help
Internal Variable

_name Variable

string help
Internal Variable

_symbol Variable

string help
Internal Variable

_tokenURIs Variable

mapping(uint256 => string) help
Internal Variable

_baseURI Variable

string help
Internal Variable

_supportedInterfaces Variable

mapping(bytes4 => bool) help
Internal Variable

_owner Variable

address help
Internal Variable

Functions Expand All Collapse All

owner keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function owner() public view returns (address) {
  return _owner;
}

renounceOwnership keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function renounceOwnership() public virtual onlyOwner {
  emit OwnershipTransferred(_owner, address(0));
  _owner = address(0);
}

transferOwnership keyboard_arrow_up

Parameters help

Name Type
newOwner
address help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Requirements help

Source Code
function transferOwnership(address newOwner) public virtual onlyOwner {
  require(newOwner != address(0), "Ownable: new owner is the zero address");
  emit OwnershipTransferred(_owner, newOwner);
  _owner = newOwner;
}

supportsInterface keyboard_arrow_up

Parameters help

Name Type
interfaceId
bytes4 help

Properties

Visibility help public
Mutability help view
Source Code
function supportsInterface(bytes4 interfaceId)
  public
  view
  override
  returns (bool)
{
  return _supportedInterfaces[interfaceId];
}

Parameters help

Name Type
owner
address help

Properties

Visibility help public
Mutability help view

Requirements help

Source Code
function balanceOf(address owner) public view override returns (uint256) {
  require(owner != address(0), "ERC721: balance query for the zero address");

  return _holderTokens[owner].length();
}

ownerOf keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function ownerOf(uint256 tokenId) public view override returns (address) {
  return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
}

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function name() public view override returns (string memory) {
  return _name;
}

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function symbol() public view override returns (string memory) {
  return _symbol;
}

tokenURI keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help view

Requirements help

null
Source Code
function tokenURI(uint256 tokenId)
  public
  view
  override
  returns (string memory)
{
  require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

  //this line altered from
  //string memory _tokenURI = _tokenURIs[tokenId];
  //use of gas to manipulate strings can be avoided by putting them together at time of retrieval rather than in the token creation transaction.
  string memory _tokenURI = putTogetherMetadataString(tokenId);

  // If there is no base URI, return the token URI.
  if (bytes(baseURI()).length == 0) {
    return _tokenURI;
  }
  // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
  if (bytes(_tokenURI).length > 0) {
    return string(abi.encodePacked(baseURI(), _tokenURI));
  }
  // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
  return string(abi.encodePacked(baseURI(), tokenId.toString()));
}

baseURI keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function baseURI() public view returns (string memory) {
  return _baseURI;
}

tokenOfOwnerByIndex keyboard_arrow_up

Parameters help

Name Type
owner
address help
index
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function tokenOfOwnerByIndex(address owner, uint256 index)
  public
  view
  override
  returns (uint256)
{
  return _holderTokens[owner].at(index);
}

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function totalSupply() public view override returns (uint256) {
  // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
  return _tokenOwners.length();
}

tokenByIndex keyboard_arrow_up

Parameters help

Name Type
index
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function tokenByIndex(uint256 index) public view override returns (uint256) {
  (uint256 tokenId, ) = _tokenOwners.at(index);
  return tokenId;
}

Parameters help

Name Type
to
address help
tokenId
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function approve(address to, uint256 tokenId) public virtual override {
  address owner = ownerOf(tokenId);
  require(to != owner, "ERC721: approval to current owner");

  require(
    _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
    "ERC721: approve caller is not owner nor approved for all"
  );

  _approve(to, tokenId);
}

getApproved keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help view

Requirements help

null
Source Code
function getApproved(uint256 tokenId) public view override returns (address) {
  require(_exists(tokenId), "ERC721: approved query for nonexistent token");

  return _tokenApprovals[tokenId];
}

setApprovalForAll keyboard_arrow_up

Parameters help

Name Type
operator
address help
approved
bool help

Properties

Visibility help public
Mutability help transaction

Requirements help

Source Code
function setApprovalForAll(address operator, bool approved)
  public
  virtual
  override
{
  require(operator != _msgSender(), "ERC721: approve to caller");

  _operatorApprovals[_msgSender()][operator] = approved;
  emit ApprovalForAll(_msgSender(), operator, approved);
}

isApprovedForAll keyboard_arrow_up

Parameters help

Name Type
owner
address help
operator
address help

Properties

Visibility help public
Mutability help view
Source Code
function isApprovedForAll(address owner, address operator)
  public
  view
  override
  returns (bool)
{
  return _operatorApprovals[owner][operator];
}

Parameters help

Name Type
from
address help
to
address help
tokenId
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function transferFrom(
  address from,
  address to,
  uint256 tokenId
) public virtual override {
  //solhint-disable-next-line max-line-length
  require(
    _isApprovedOrOwner(_msgSender(), tokenId),
    "ERC721: transfer caller is not owner nor approved"
  );

  _transfer(from, to, tokenId);
}

safeTransferFrom keyboard_arrow_up

Parameters help

Name Type
from
address help
to
address help
tokenId
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function safeTransferFrom(
  address from,
  address to,
  uint256 tokenId
) public virtual override {
  safeTransferFrom(from, to, tokenId, "");
}

safeTransferFrom keyboard_arrow_up

Parameters help

Name Type
from
address help
to
address help
tokenId
uint256 help
_data
bytes help

Properties

Visibility help public
Mutability help transaction
Source Code
function safeTransferFrom(
  address from,
  address to,
  uint256 tokenId,
  bytes memory _data
) public virtual override {
  require(
    _isApprovedOrOwner(_msgSender(), tokenId),
    "ERC721: transfer caller is not owner nor approved"
  );
  _safeTransfer(from, to, tokenId, _data);
}

setBaseURI keyboard_arrow_up

Parameters help

Name Type
baseURI_
string help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function setBaseURI(string calldata baseURI_) external onlyOwner {
  _setBaseURI(baseURI_);
}

setLiquidityTokenAccepted keyboard_arrow_up

Parameters help

Name Type
token
address help
accepted
bool help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function setLiquidityTokenAccepted(address token, bool accepted)
  external
  onlyOwner
{
  tokenAccepted[token] = accepted;
}

setLiquidityTokenAcceptedMulti keyboard_arrow_up

Parameters help

Name Type
tokens
address[] help
accepted
bool help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function setLiquidityTokenAcceptedMulti(
  address[] calldata tokens,
  bool accepted
) external onlyOwner {
  for (uint256 i = 0; i < tokens.length; i++) {
    tokenAccepted[tokens[i]] = accepted;
  }
}

setSyncMinimum keyboard_arrow_up

Parameters help

Name Type
newMinimum
uint256 help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function setSyncMinimum(uint256 newMinimum) public onlyOwner {
  require(
    newMinimum < syncMinimum,
    "increasing minimum sync required is not permitted"
  );
  syncMinimum = newMinimum;
}

setPriceOracle keyboard_arrow_up

Parameters help

Name Type
o
Oracle help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function setPriceOracle(Oracle o) external onlyOwner {
  priceChecker = o;
}

toggleLuckyBonus keyboard_arrow_up

Parameters help

Name Type
enabled
bool help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function toggleLuckyBonus(bool enabled) external onlyOwner {
  luckyEnabled = enabled;
}

recordSyncAndTokens keyboard_arrow_up

Parameters help

Name Type
tokens
address[] help

Properties

Visibility help public
Mutability help transaction

Modifiers help

Source Code
function recordSyncAndTokens(address[] calldata tokens) external onlyOwner {
  recordSyncSupply();
  for (uint256 i = 0; i < tokens.length; i++) {
    recordTokenSupply(tokens[i]);
  }
}

cashOutDivs keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function cashOutDivs(uint256 tokenId) external {
  require(msg.sender == ownerOf(tokenId), "only token owner can call this");
  require(gradualDivsById[tokenId], "must be in quarterly dividends mode");

  //record current Sync supply and liquidity token supply for the day if needed
  recordSyncSupply();
  recordTokenSupply(lAddrById[tokenId]);

  //reward user with appropriate amount. If none is due it will provide an amount of 0 tokens.
  uint256 divs = dividendsOf(tokenId);
  syncToken._mint(msg.sender, divs);

  //register the timestamp of this transaction so future div payouts can be accurately calculated
  lastDivsCashoutById[tokenId] = block.timestamp;

  //update read variables
  totalDivsCashoutById[tokenId] = totalDivsCashoutById[tokenId].add(divs);

  emit DivsPaid(lAddrById[tokenId], divs, tokenId);
}

matureCBOND keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function matureCBOND(uint256 tokenId) public {
  require(msg.sender == ownerOf(tokenId), "only token owner can call this");
  require(
    block.timestamp > termLengthById[tokenId].add(timestampById[tokenId]),
    "cbond term not yet completed"
  );

  //record current Sync supply and liquidity token supply for the day if needed
  recordSyncSupply();
  recordTokenSupply(lAddrById[tokenId]);

  //amount of sync provided to user is initially deposited amount plus interest
  uint256 syncRetrieved = syncRewardedOnMaturity[tokenId];

  //provide user with their Sync tokens and their initially deposited liquidity tokens
  uint256 beforeMint = syncToken.balanceOf(msg.sender);
  syncToken._mint(msg.sender, syncRetrieved);
  require(
    IERC20(lAddrById[tokenId]).transfer(msg.sender, lTokenAmountById[tokenId]),
    "transfer must succeed"
  );

  //update read only counter
  totalCBONDSCashedout = totalCBONDSCashedout.add(1);
  emit Matured(
    lAddrById[tokenId],
    syncRetrieved,
    lTokenAmountById[tokenId],
    tokenId
  );

  //burn the nft
  _burn(tokenId);
}

createCBOND keyboard_arrow_up

Parameters help

Name Type
liquidityToken
address help
amount
uint256 help
syncMaximum
uint256 help
secondsInTerm
uint256 help
gradualDivs
bool help

Properties

Visibility help public
Mutability help transaction

Requirements help

null
Source Code
function createCBOND(
  address liquidityToken,
  uint256 amount,
  uint256 syncMaximum,
  uint256 secondsInTerm,
  bool gradualDivs
) external returns (uint256) {
  return
    _createCBOND(
      liquidityToken,
      amount,
      syncMaximum,
      secondsInTerm,
      gradualDivs,
      msg.sender
    );
}

putTogetherMetadataString keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function putTogetherMetadataString(uint256 tokenId)
  public
  view
  returns (string memory)
{
  //TODO: add the rest of the variables, separate with appropriate url variable separators for ease of use
  string memory isDivs = gradualDivsById[tokenId] ? "true" : "false";
  return
    string(
      abi.encodePacked(
        "/?tokenId=",
        tokenId.toString(),
        "&lAddr=",
        lAddrById[tokenId].toString(),
        "&syncPrice=",
        syncPriceById[tokenId].toString(),
        "&syncAmount=",
        syncAmountById[tokenId].toString(),
        "&mPayout=",
        syncRewardedOnMaturity[tokenId].toString(),
        "&lPrice=",
        lTokenPriceById[tokenId].toString(),
        "&lAmount=",
        lTokenAmountById[tokenId].toString(),
        "&startTime=",
        timestampById[tokenId].toString(),
        "&isDivs=",
        isDivs,
        "&termLength=",
        termLengthById[tokenId].toString(),
        "&divsNow=",
        dividendsOf(tokenId).toString()
      )
    );
}

getTime keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function getTime() public view returns (uint256) {
  return block.timestamp;
}

dividendsOf keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help view

Requirements help

Source Code
function dividendsOf(uint256 tokenId) public view returns (uint256) {
  //determine the number of periods worth of divs the token owner is owed, by subtracting the current period by the period when divs were last withdrawn.
  require(lastDivsCashoutById[tokenId] >= timestampById[tokenId], "dof1");
  uint256 lastCashoutInPeriod = lastDivsCashoutById[tokenId]
  .sub(timestampById[tokenId])
  .div(QUARTER_LENGTH); //0 - first quarter, 1 - second, etc. This variable also represents the number of quarters previously cashed out
  require(block.timestamp >= timestampById[tokenId], "dof2");
  uint256 currentCashoutInPeriod = block
  .timestamp
  .sub(timestampById[tokenId])
  .div(QUARTER_LENGTH);
  require(currentCashoutInPeriod >= lastCashoutInPeriod, "dof3");
  uint256 periodsToCashout = currentCashoutInPeriod.sub(lastCashoutInPeriod);

  //only accrue divs before the maturation date. The final div payment will be paid as part of the matureCBOND transaction, so set the maximum number of periods to cash out be one less than the ultimate total.
  if (currentCashoutInPeriod >= termLengthById[tokenId].div(90 days)) {
    //possible for lastCashout period to be greater due to being able to cash out after CBOND has ended (which records lastCashout as being after that date, despite only paying out for earlier periods). In this case, set periodsToCashout to 0 and ultimately return 0, there are no divs left.
    if (lastCashoutInPeriod > termLengthById[tokenId].div(90 days).sub(1)) {
      periodsToCashout = 0;
    } else {
      periodsToCashout = termLengthById[tokenId].div(90 days).sub(1).sub(
        lastCashoutInPeriod
      );
    }
  }
  //multiply the number of periods to pay out with the amount of divs owed for one period. Note: if this is a Quarterly Cbond, syncInterestById will have been recorded as the interest per quarter, rather than the total interest for the Cbond, as with a normal Cbond.
  uint256 quarterlyDividend = syncInterestById[tokenId];
  return
    periodsToCashout.mul(syncAmountById[tokenId]).mul(quarterlyDividend).div(
      PERCENTAGE_PRECISION
    );
}

getSyncRequiredForCreation keyboard_arrow_up

Parameters help

Name Type
liquidityToken
IERC20 help
amount
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function getSyncRequiredForCreation(IERC20 liquidityToken, uint256 amount)
  external
  view
  returns (uint256)
{
  return
    priceChecker.liquidityValues(address(liquidityToken)).mul(amount).div(
      priceChecker.syncValue()
    );
}

getCbondTotalReturn keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help
syncAmount
uint256 help
liqAddr
address help
duration
uint256 help
isDivs
bool help

Properties

Visibility help public
Mutability help view
Source Code
function getCbondTotalReturn(
  uint256 tokenId,
  uint256 syncAmount,
  address liqAddr,
  uint256 duration,
  bool isDivs
) public view returns (uint256 interestRate, uint256 totalReturn) {
  // This is an integer math translation of P*(1+I) where P is principle I is interest rate. The new, equivalent formula is P*(c+I*c)/c where c is a constant of amount PERCENTAGE_PRECISION.

  interestRate = getCbondInterestRateNow(
    liqAddr,
    duration,
    getLuckyExtra(tokenId),
    isDivs
  );
  totalReturn = syncAmount.mul(PERCENTAGE_PRECISION.add(interestRate)).div(
    PERCENTAGE_PRECISION
  );
}

getCbondInterestRateNow keyboard_arrow_up

Parameters help

Name Type
liqAddr
address help
duration
uint256 help
luckyExtra
uint256 help
quarterly
bool help

Properties

Visibility help public
Mutability help view
Source Code
function getCbondInterestRateNow(
  address liqAddr,
  uint256 duration,
  uint256 luckyExtra,
  bool quarterly
) public view returns (uint256) {
  return
    getCbondInterestRate(
      duration,
      liqTokenTotalsByDay[liqAddr][lastDayTokenSupplyUpdated[liqAddr]],
      liqTokenTotalsByDay[liqAddr][getDay(block.timestamp)],
      syncSupplyByDay[lastDaySyncSupplyUpdated],
      syncSupplyByDay[getDay(block.timestamp)],
      interestRateByDay[lastDaySyncSupplyUpdated],
      luckyExtra,
      quarterly
    );
}

getCbondInterestRate keyboard_arrow_up

Parameters help

Name Type
duration
uint256 help
liqTotalLast
uint256 help
liqTotalCurrent
uint256 help
syncTotalLast
uint256 help
syncTotalCurrent
uint256 help
lastBaseInterestRate
uint256 help
luckyExtra
uint256 help
quarterly
bool help

Properties

Visibility help public
Mutability help view
Source Code
function getCbondInterestRate(
  uint256 duration,
  uint256 liqTotalLast,
  uint256 liqTotalCurrent,
  uint256 syncTotalLast,
  uint256 syncTotalCurrent,
  uint256 lastBaseInterestRate,
  uint256 luckyExtra,
  bool quarterly
) public view returns (uint256) {
  uint256 liquidityPairIncentiveRate = getLiquidityPairIncentiveRate(
    liqTotalCurrent,
    liqTotalLast
  );
  uint256 baseInterestRate = getBaseInterestRate(
    lastBaseInterestRate,
    syncTotalCurrent,
    syncTotalLast
  );
  if (!quarterly) {
    return
      getDurationRate(
        duration,
        baseInterestRate.add(liquidityPairIncentiveRate).add(luckyExtra)
      );
  } else {
    uint256 numYears = duration.div(YEAR_LENGTH);
    require(numYears > 0, "invalid duration"); //Quarterly Cbonds must have a duration 1 year or longer.
    uint256 numQuarters = duration.div(QUARTER_LENGTH);
    uint256 termModifier = RISK_FACTOR.mul(numYears.mul(4).sub(1));
    //Interest rate is the sum of base interest rate, liquidity incentive rate, and risk/term based modifier. Because this is the Quarterly Cbond rate, we also divide by the number of quarters in the Cbond, to set the recorded rate to the amount withdrawable per quarter.
    return
      baseInterestRate.add(liquidityPairIncentiveRate).add(luckyExtra).add(
        termModifier
      );
  }
}

getLuckyExtra keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function getLuckyExtra(uint256 tokenId) public view returns (uint256) {
  if (luckyEnabled) {
    if (tokenId.mod(100) == 77) {
      return LUCKY_EXTRAS[0];
    }
    if (tokenId.mod(1000) == 777) {
      return LUCKY_EXTRAS[1];
    }
  }
  return 0;
}

getDurationRate keyboard_arrow_up

Parameters help

Name Type
duration
uint help
baseInterestRate
uint help

Properties

Visibility help public
Mutability help view

Requirements help

One or more of the following: - duration must be equal to TERM_DURATIONS for 4 - OR duration must be equal to TERM_DURATIONS for 3 - OR duration must be equal to TERM_DURATIONS for 2 - OR duration must be equal to TERM_DURATIONS for 1 - OR duration must be equal to TERM_DURATIONS for 0
Source Code
function getDurationRate(uint256 duration, uint256 baseInterestRate)
  public
  view
  returns (uint256)
{
  require(
    duration == TERM_DURATIONS[0] ||
      duration == TERM_DURATIONS[1] ||
      duration == TERM_DURATIONS[2] ||
      duration == TERM_DURATIONS[3] ||
      duration == TERM_DURATIONS[4],
    "Invalid CBOND term length provided"
  );

  if (duration == TERM_DURATIONS[0]) {
    return baseInterestRate;
  }
  if (duration == TERM_DURATIONS[1]) {
    uint256 preExponential = PERCENTAGE_PRECISION.add(baseInterestRate).add(
      RISK_FACTOR
    );
    uint256 exponential = preExponential.mul(preExponential).div(
      PERCENTAGE_PRECISION
    );
    return exponential.sub(PERCENTAGE_PRECISION);
  }
  if (duration == TERM_DURATIONS[2]) {
    //1 year
    uint256 preExponential = PERCENTAGE_PRECISION.add(baseInterestRate).add(
      RISK_FACTOR.mul(3)
    );
    uint256 exponential = preExponential.mul(preExponential).div(
      PERCENTAGE_PRECISION
    );
    for (uint8 i = 0; i < 2; i++) {
      exponential = exponential.mul(preExponential).div(PERCENTAGE_PRECISION);
    }
    return exponential.sub(PERCENTAGE_PRECISION);
  }
  if (duration == TERM_DURATIONS[3]) {
    //2 years
    uint256 preExponential = PERCENTAGE_PRECISION.add(baseInterestRate).add(
      RISK_FACTOR.mul(7)
    );
    uint256 exponential = preExponential.mul(preExponential).div(
      PERCENTAGE_PRECISION
    );
    for (uint8 i = 0; i < 6; i++) {
      exponential = exponential.mul(preExponential).div(PERCENTAGE_PRECISION);
    }
    return exponential.sub(PERCENTAGE_PRECISION);
  }
  if (duration == TERM_DURATIONS[4]) {
    //3 years
    uint256 preExponential = PERCENTAGE_PRECISION.add(baseInterestRate).add(
      RISK_FACTOR.mul(11)
    );
    uint256 exponential = preExponential.mul(preExponential).div(
      PERCENTAGE_PRECISION
    );
    for (uint8 i = 0; i < 10; i++) {
      exponential = exponential.mul(preExponential).div(PERCENTAGE_PRECISION);
    }
    return exponential.sub(PERCENTAGE_PRECISION);
  }
}

getLiquidityPairIncentiveRate keyboard_arrow_up

Parameters help

Name Type
totalToday
uint256 help
totalYesterday
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function getLiquidityPairIncentiveRate(
  uint256 totalToday,
  uint256 totalYesterday
) public view returns (uint256) {
  //instead of reverting due to division by zero, if tokens in this contract go to zero give the max bonus
  if (totalToday == 0) {
    return INCENTIVE_MAX_PERCENT;
  }
  return
    Math.min(
      INCENTIVE_MAX_PERCENT,
      INCENTIVE_MAX_PERCENT.mul(totalYesterday).div(totalToday)
    );
}

getBaseInterestRate keyboard_arrow_up

Parameters help

Name Type
lastdayInterestRate
uint256 help
syncSupplyToday
uint256 help
syncSupplyLast
uint256 help

Properties

Visibility help public
Mutability help pure
Source Code
function getBaseInterestRate(
  uint256 lastdayInterestRate,
  uint256 syncSupplyToday,
  uint256 syncSupplyLast
) public pure returns (uint256) {
  return
    Math.min(
      MAXIMUM_BASE_INTEREST_RATE,
      Math.max(
        MINIMUM_BASE_INTEREST_RATE,
        lastdayInterestRate.mul(syncSupplyToday).div(syncSupplyLast)
      )
    );
}

getCbondInterestRateIfUpdated keyboard_arrow_up

Parameters help

Name Type
liqAddr
address help
duration
uint256 help
luckyExtra
uint256 help
quarterly
bool help

Properties

Visibility help public
Mutability help view
Source Code
function getCbondInterestRateIfUpdated(
  address liqAddr,
  uint256 duration,
  uint256 luckyExtra,
  bool quarterly
) public view returns (uint256) {
  (
    uint256 lastSupply,
    uint256 currentSupply,
    uint256 lastTSupply,
    uint256 currentTSupply,
    uint256 lastInterestRate
  ) = getSuppliesIfUpdated(liqAddr);
  return
    getCbondInterestRate(
      duration,
      lastTSupply,
      currentTSupply,
      lastSupply,
      currentSupply,
      lastInterestRate,
      luckyExtra,
      quarterly
    );
}

getSuppliesNow keyboard_arrow_up

Parameters help

Name Type
tokenAddr
address help

Properties

Visibility help public
Mutability help view
Source Code
function getSuppliesNow(address tokenAddr)
  public
  view
  returns (
    uint256 lastSupply,
    uint256 currentSupply,
    uint256 lastTSupply,
    uint256 currentTSupply,
    uint256 lastInterestRate
  )
{
  currentSupply = syncSupplyByDay[currentDaySyncSupplyUpdated];
  lastSupply = syncSupplyByDay[lastDaySyncSupplyUpdated];
  lastInterestRate = interestRateByDay[lastDaySyncSupplyUpdated];
  currentTSupply = liqTokenTotalsByDay[tokenAddr][
    currentDayTokenSupplyUpdated[tokenAddr]
  ];
  lastTSupply = liqTokenTotalsByDay[tokenAddr][
    lastDayTokenSupplyUpdated[tokenAddr]
  ];
}

getSuppliesIfUpdated keyboard_arrow_up

Parameters help

Name Type
tokenAddr
address help

Properties

Visibility help public
Mutability help view
Source Code
function getSuppliesIfUpdated(address tokenAddr)
  public
  view
  returns (
    uint256 lastSupply,
    uint256 currentSupply,
    uint256 lastTSupply,
    uint256 currentTSupply,
    uint256 lastInterestRate
  )
{
  uint256 day = getDay(block.timestamp);
  if (liqTokenTotalsByDay[tokenAddr][getDay(block.timestamp)] == 0) {
    currentTSupply = IERC20(tokenAddr).balanceOf(address(this));
    lastTSupply = liqTokenTotalsByDay[tokenAddr][
      currentDayTokenSupplyUpdated[tokenAddr]
    ];
  } else {
    currentTSupply = liqTokenTotalsByDay[tokenAddr][
      currentDayTokenSupplyUpdated[tokenAddr]
    ];
    lastTSupply = liqTokenTotalsByDay[tokenAddr][
      lastDayTokenSupplyUpdated[tokenAddr]
    ];
  }
  if (syncSupplyByDay[day] == 0) {
    currentSupply = syncToken.totalSupply();
    lastSupply = syncSupplyByDay[currentDaySyncSupplyUpdated];
    //TODO: interest rate
    lastInterestRate = interestRateByDay[currentDaySyncSupplyUpdated];
  } else {
    currentSupply = syncSupplyByDay[currentDaySyncSupplyUpdated];
    lastSupply = syncSupplyByDay[lastDaySyncSupplyUpdated];
    lastInterestRate = interestRateByDay[lastDaySyncSupplyUpdated];
  }
}

recordSyncSupply keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help transaction
Source Code
function recordSyncSupply() public {
  if (syncSupplyByDay[getDay(block.timestamp)] == 0) {
    uint256 day = getDay(block.timestamp);
    syncSupplyByDay[day] = syncToken.totalSupply();
    lastDaySyncSupplyUpdated = currentDaySyncSupplyUpdated;
    currentDaySyncSupplyUpdated = day;

    //interest rate
    interestRateByDay[day] = getBaseInterestRate(
      interestRateByDay[lastDaySyncSupplyUpdated],
      syncSupplyByDay[day],
      syncSupplyByDay[lastDaySyncSupplyUpdated]
    );
  }
}

getDay keyboard_arrow_up

Parameters help

Name Type
timestamp
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function getDay(uint256 timestamp) public view returns (uint256) {
  return timestamp.sub(STARTING_TIME).div(24 hours).add(1);
}

getDayNow keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function getDayNow() public view returns (uint256) {
  return getDay(block.timestamp);
}

Internal Functions Expand All Collapse All

Internal functions are parts of the contract that can't be used directly, but instead are used by the public functions listed above.

internal CBOND._createCBOND keyboard_arrow_up

Parameters help

Name Type
liquidityToken
address help
amount
uint256 help
syncMaximum
uint256 help
secondsInTerm
uint256 help
gradualDivs
bool help
sender
address help

Properties

Visibility help private
Mutability help transaction

Requirements help

null
Source Code
function _createCBOND(
  address liquidityToken,
  uint256 amount,
  uint256 syncMaximum,
  uint256 secondsInTerm,
  bool gradualDivs,
  address sender
) private returns (uint256) {
  require(
    tokenAccepted[liquidityToken],
    "liquidity token must be on the list of approved tokens"
  );

  //record current Sync supply and liquidity token supply for the day if needed
  recordSyncSupply();
  recordTokenSupply(liquidityToken);

  //determine amount of Sync required, given the amount of liquidity tokens specified, and transfer that amount from the user
  uint256 liquidityValue = priceChecker.liquidityValues(liquidityToken);
  uint256 syncValue = priceChecker.syncValue();
  //Since syncRequired is the exact amount of Sync that will be transferred from the user, integer division truncations propagating to other values derived from this one is the correct behavior.
  uint256 syncRequired = liquidityValue.mul(amount).div(syncValue);
  require(
    syncRequired >= syncMinimum,
    "input tokens too few, sync transferred must be above the minimum"
  );
  require(
    syncRequired <= syncMaximum,
    "price changed too much since transaction submitted"
  );
  require(syncRequired <= MAX_SYNC_GLOBAL, "CBOND amount too large");
  syncToken.transferFrom(sender, address(this), syncRequired);
  require(
    IERC20(liquidityToken).transferFrom(sender, address(this), amount),
    "transfer must succeed"
  );

  //burn sync tokens provided
  syncToken.burn(syncRequired);

  //get the token id of the new NFT
  uint256 tokenId = _getNextTokenId();

  //set all nft variables
  lAddrById[tokenId] = liquidityToken;
  syncPriceById[tokenId] = syncValue;
  syncAmountById[tokenId] = syncRequired;
  lTokenPriceById[tokenId] = liquidityValue;
  lTokenAmountById[tokenId] = amount;
  timestampById[tokenId] = block.timestamp;
  lastDivsCashoutById[tokenId] = block.timestamp;
  gradualDivsById[tokenId] = gradualDivs;
  termLengthById[tokenId] = secondsInTerm;

  //set the interest rate and final maturity withdraw amount
  setInterestRate(
    tokenId,
    syncRequired,
    liquidityToken,
    secondsInTerm,
    gradualDivs
  );

  //update global counters
  cbondsMaturingByDay[
    getDay(block.timestamp.add(secondsInTerm))
  ] = cbondsMaturingByDay[getDay(block.timestamp.add(secondsInTerm))].add(1);
  cbondsHeldByUser[sender][cbondsHeldByUserCursor[sender]] = tokenId;
  cbondsHeldByUserCursor[sender] = cbondsHeldByUserCursor[sender].add(1);
  totalCBONDS = totalCBONDS.add(1);
  totalSYNCLocked = totalSYNCLocked.add(syncRequired);
  totalLiquidityLockedByPair[liquidityToken] = totalLiquidityLockedByPair[
    liquidityToken
  ]
  .add(amount);

  //create NFT
  _safeMint(sender, tokenId);
  _incrementTokenId();

  //submit event
  emit Created(
    liquidityToken,
    syncRequired,
    amount,
    syncValue,
    liquidityValue,
    tokenId
  );
  return tokenId;
}

internal CBOND._incrementTokenId keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help private
Mutability help transaction
Source Code
function _incrementTokenId() private {
  _currentTokenId = _currentTokenId.add(1);
}

internal CBOND._getNextTokenId keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help private
Mutability help view
Source Code
function _getNextTokenId() private view returns (uint256) {
  return _currentTokenId.add(1);
}

internal CBOND.setInterestRate keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help
syncRequired
uint256 help
liquidityToken
address help
secondsInTerm
uint256 help
gradualDivs
bool help

Properties

Visibility help private
Mutability help transaction
Source Code
function setInterestRate(
  uint256 tokenId,
  uint256 syncRequired,
  address liquidityToken,
  uint256 secondsInTerm,
  bool gradualDivs
) private {
  (
    uint256 lastSupply,
    uint256 currentSupply,
    uint256 lastTSupply,
    uint256 currentTSupply,
    uint256 lastInterestRate
  ) = getSuppliesNow(liquidityToken);
  (uint256 interestRate, uint256 totalReturn) = getCbondTotalReturn(
    tokenId,
    syncRequired,
    liquidityToken,
    secondsInTerm,
    gradualDivs
  );
  syncRewardedOnMaturity[tokenId] = totalReturn;
  syncInterestById[tokenId] = interestRate;
  if (gradualDivs) {
    require(
      secondsInTerm >= TERM_DURATIONS[2],
      "dividend bearing CBONDs must be at least 1 year duration"
    );
    totalQuarterlyCBONDS = totalQuarterlyCBONDS.add(1);
  }
}

internal CBOND.recordTokenSupply keyboard_arrow_up

Parameters help

Name Type
tokenAddr
address help

Properties

Visibility help private
Mutability help transaction
Source Code
function recordTokenSupply(address tokenAddr) private {
  if (liqTokenTotalsByDay[tokenAddr][getDay(block.timestamp)] == 0) {
    uint256 day = getDay(block.timestamp);
    liqTokenTotalsByDay[tokenAddr][day] = IERC20(tokenAddr).balanceOf(
      address(this)
    );
    lastDayTokenSupplyUpdated[tokenAddr] = currentDayTokenSupplyUpdated[
      tokenAddr
    ];
    currentDayTokenSupplyUpdated[tokenAddr] = day;
  }
}

internal ERC721._safeTransfer keyboard_arrow_up

Parameters help

Name Type
from
address help
to
address help
tokenId
uint256 help
_data
bytes help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _safeTransfer(
  address from,
  address to,
  uint256 tokenId,
  bytes memory _data
) internal virtual {
  _transfer(from, to, tokenId);
  require(
    _checkOnERC721Received(from, to, tokenId, _data),
    "ERC721: transfer to non ERC721Receiver implementer"
  );
}

internal ERC721._exists keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help internal
Mutability help view
Source Code
function _exists(uint256 tokenId) internal view returns (bool) {
  return _tokenOwners.contains(tokenId);
}

internal ERC721._isApprovedOrOwner keyboard_arrow_up

Parameters help

Name Type
spender
address help
tokenId
uint256 help

Properties

Visibility help internal
Mutability help view

Requirements help

null
Source Code
function _isApprovedOrOwner(address spender, uint256 tokenId)
  internal
  view
  returns (bool)
{
  require(_exists(tokenId), "ERC721: operator query for nonexistent token");
  address owner = ownerOf(tokenId);
  return (spender == owner ||
    getApproved(tokenId) == spender ||
    isApprovedForAll(owner, spender));
}

internal ERC721._safeMint keyboard_arrow_up

Parameters help

Name Type
to
address help
tokenId
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _safeMint(address to, uint256 tokenId) internal virtual {
  _safeMint(to, tokenId, "");
}

internal ERC721._safeMint keyboard_arrow_up

Parameters help

Name Type
to
address help
tokenId
uint256 help
_data
bytes help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _safeMint(
  address to,
  uint256 tokenId,
  bytes memory _data
) internal virtual {
  _mint(to, tokenId);
  require(
    _checkOnERC721Received(address(0), to, tokenId, _data),
    "ERC721: transfer to non ERC721Receiver implementer"
  );
}

internal ERC721._mint keyboard_arrow_up

Parameters help

Name Type
to
address help
tokenId
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _mint(address to, uint256 tokenId) internal virtual {
  require(to != address(0), "ERC721: mint to the zero address");
  require(!_exists(tokenId), "ERC721: token already minted");

  _beforeTokenTransfer(address(0), to, tokenId);

  _holderTokens[to].add(tokenId);

  _tokenOwners.set(tokenId, to);

  emit Transfer(address(0), to, tokenId);
}

internal ERC721._burn keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _burn(uint256 tokenId) internal virtual {
  address owner = ownerOf(tokenId);

  _beforeTokenTransfer(owner, address(0), tokenId);

  // Clear approvals
  _approve(address(0), tokenId);

  // Clear metadata (if any)
  if (bytes(_tokenURIs[tokenId]).length != 0) {
    delete _tokenURIs[tokenId];
  }

  _holderTokens[owner].remove(tokenId);

  _tokenOwners.remove(tokenId);

  emit Transfer(owner, address(0), tokenId);
}

internal ERC721._transfer keyboard_arrow_up

Parameters help

Name Type
from
address help
to
address help
tokenId
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _transfer(
  address from,
  address to,
  uint256 tokenId
) internal virtual {
  require(
    ownerOf(tokenId) == from,
    "ERC721: transfer of token that is not own"
  );
  require(to != address(0), "ERC721: transfer to the zero address");

  _beforeTokenTransfer(from, to, tokenId);

  // Clear approvals from the previous owner
  _approve(address(0), tokenId);

  _holderTokens[from].remove(tokenId);
  _holderTokens[to].add(tokenId);

  _tokenOwners.set(tokenId, to);

  emit Transfer(from, to, tokenId);
}

internal ERC721._setTokenURI keyboard_arrow_up

Parameters help

Name Type
tokenId
uint256 help
_tokenURI
string help

Properties

Visibility help internal
Mutability help transaction

Requirements help

null
Source Code
function _setTokenURI(uint256 tokenId, string memory _tokenURI)
  internal
  virtual
{
  require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
  _tokenURIs[tokenId] = _tokenURI;
}

internal ERC721._setBaseURI keyboard_arrow_up

Parameters help

Name Type
baseURI_
string help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _setBaseURI(string memory baseURI_) internal virtual {
  _baseURI = baseURI_;
}

internal ERC721._checkOnERC721Received keyboard_arrow_up

Parameters help

Name Type
from
address help
to
address help
tokenId
uint256 help
_data
bytes help

Properties

Visibility help private
Mutability help transaction
Source Code
function _checkOnERC721Received(
  address from,
  address to,
  uint256 tokenId,
  bytes memory _data
) private returns (bool) {
  if (!to.isContract()) {
    return true;
  }
  bytes memory returndata = to.functionCall(
    abi.encodeWithSelector(
      IERC721Receiver(to).onERC721Received.selector,
      _msgSender(),
      from,
      tokenId,
      _data
    ),
    "ERC721: transfer to non ERC721Receiver implementer"
  );
  bytes4 retval = abi.decode(returndata, (bytes4));
  return (retval == _ERC721_RECEIVED);
}

internal ERC721._approve keyboard_arrow_up

Parameters help

Name Type
to
address help
tokenId
uint256 help

Properties

Visibility help private
Mutability help transaction
Source Code
function _approve(address to, uint256 tokenId) private {
  _tokenApprovals[tokenId] = to;
  emit Approval(ownerOf(tokenId), to, tokenId);
}

internal ERC721._beforeTokenTransfer keyboard_arrow_up

Parameters help

Name Type
from
address help
to
address help
tokenId
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function _beforeTokenTransfer(
  address from,
  address to,
  uint256 tokenId
) internal virtual {}

internal Context._msgSender keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help view
Source Code
function _msgSender() internal view virtual returns (address payable) {
  return msg.sender;
}

internal Context._msgData keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help view
Source Code
function _msgData() internal view virtual returns (bytes memory) {
  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
  return msg.data;
}

internal ERC165.constructor keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help transaction

Requirements help

Source Code
constructor() internal {
  // Derived contracts need only register support for their own interfaces,
  // we register support for ERC165 itself here
  _registerInterface(_INTERFACE_ID_ERC165);
}

internal ERC165._registerInterface keyboard_arrow_up

Parameters help

Name Type
interfaceId
bytes4 help

Properties

Visibility help internal
Mutability help transaction

Requirements help

Source Code
function _registerInterface(bytes4 interfaceId) internal virtual {
  require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
  _supportedInterfaces[interfaceId] = true;
}

internal Ownable.constructor keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help transaction
Source Code
constructor() internal {
  address msgSender = _msgSender();
  _owner = msgSender;
  emit OwnershipTransferred(address(0), msgSender);
}

internal Context._msgSender keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help view
Source Code
function _msgSender() internal view virtual returns (address payable) {
  return msg.sender;
}

internal Context._msgData keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help internal
Mutability help view
Source Code
function _msgData() internal view virtual returns (bytes memory) {
  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
  return msg.data;
}