Blockwell

Illuvium

ERC20

This contract is an ERC20 token.

Name Illuvium
Symbol ILV
Decimals 18
Total Supply 7,000,000 ILV

About link

Illuvium (ILV) is a cryptocurrency and operates on the Ethereum platform. Illuvium has a current supply of 7,000,000 with 651,440.25822608 in circulation. The last known price of Illuvium is 94.70447146 USD and is down -17.11 over the last 24 hours. It is currently trading on 13 active market(s) with $7,163,868.25 traded over the last 24 hours. More information can be found at https://illuvium.io/.

Stats

Public Functions 24
Event Types 9
Code Size 61,514 bytes

Events (9) keyboard_arrow_up

Approval Event

Parameters help
_owner
address help
_spender
address help
_value
uint256 help

Approved Event

Parameters help
_owner
address help
_spender
address help
_oldValue
uint256 help
_value
uint256 help

Burnt Event

Parameters help
_by
address help
_from
address help
_value
uint256 help

DelegateChanged Event

Parameters help
_of
address help
_from
address help
_to
address help

Minted Event

Parameters help
_by
address help
_to
address help
_value
uint256 help

RoleUpdated Event

Parameters help
_by
address help
_to
address help
_requested
uint256 help
_actual
uint256 help

Transfer Event

Parameters help
_from
address help
_to
address help
_value
uint256 help

Transferred Event

Parameters help
_by
address help
_from
address help
_to
address help
_value
uint256 help

VotingPowerChanged Event

Parameters help
_of
address help
_fromVal
uint256 help
_toVal
uint256 help

VotingPowerRecord Struct

Members
blockNumber
uint64 help
votingPower
uint192 help

TOKEN_UID Constant

uint256 help
0x83ecb176af7c4f35a45ff0018282e3a05a1018065da866182df12285866f5a2c

name Constant

string help
Illuvium

symbol Constant

string help
ILV

decimals Constant

uint8 help
18

FEATURE_TRANSFERS Constant

uint32 help
0x0000_0001

FEATURE_TRANSFERS_ON_BEHALF Constant

uint32 help
0x0000_0002

FEATURE_UNSAFE_TRANSFERS Constant

uint32 help
0x0000_0004

FEATURE_OWN_BURNS Constant

uint32 help
0x0000_0008

FEATURE_BURNS_ON_BEHALF Constant

uint32 help
0x0000_0010

FEATURE_DELEGATIONS Constant

uint32 help
0x0000_0020

FEATURE_DELEGATIONS_ON_BEHALF Constant

uint32 help
0x0000_0040

ROLE_TOKEN_CREATOR Constant

uint32 help
0x0001_0000

ROLE_TOKEN_DESTROYER Constant

uint32 help
0x0002_0000

ROLE_ERC20_RECEIVER Constant

uint32 help
0x0004_0000

ROLE_ERC20_SENDER Constant

uint32 help
0x0008_0000

ERC20_RECEIVED Constant

bytes4 help
0x4fc35859

DOMAIN_TYPEHASH Constant

bytes32 help
the result of calling keccak256 with "EIP712Domain(string name,uint256 chainId,address verifyingContract)"

DELEGATION_TYPEHASH Constant

bytes32 help
the result of calling keccak256 with "Delegation(address delegate,uint256 nonce,uint256 expiry)"

ROLE_ACCESS_MANAGER Constant

uint256 help
0x8000000000000000000000000000000000000000000000000000000000000000

FULL_PRIVILEGES_MASK Constant

uint256 help

totalSupply Variable

uint256 help

tokenBalances Variable

mapping(address => uint256) help

votingDelegates Variable

mapping(address => address) help

nonces Variable

mapping(address => uint256) help

userRoles Variable

mapping(address => uint256) help

votingPowerHistory Variable

mapping(address => VotingPowerRecord[]) help
Internal Variable

transferAllowances Variable

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

Functions Expand All Collapse All

features keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help view
Source Code
function features() public view returns (uint256) {
  // according to new design features are stored in zero address
  // mapping of `userRoles` structure
  return userRoles[address(0)];
}

updateFeatures keyboard_arrow_up

Parameters help

Name Type
_mask
uint256 help

Properties

Visibility help public
Mutability help transaction

Requirements help

null
Source Code
function updateFeatures(uint256 _mask) public {
  // delegate call to `updateRole`
  updateRole(address(0), _mask);
}

updateRole keyboard_arrow_up

Parameters help

Name Type
operator
address help
role
uint256 help

Properties

Visibility help public
Mutability help transaction

Requirements help

null
Source Code
function updateRole(address operator, uint256 role) public {
  // caller must have a permission to update user roles
  require(
    isSenderInRole(ROLE_ACCESS_MANAGER),
    "insufficient privileges (ROLE_ACCESS_MANAGER required)"
  );

  // evaluate the role and reassign it
  userRoles[operator] = evaluateBy(msg.sender, userRoles[operator], role);

  // fire an event
  emit RoleUpdated(msg.sender, operator, role, userRoles[operator]);
}

evaluateBy keyboard_arrow_up

Parameters help

Name Type
operator
address help
target
uint256 help
desired
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function evaluateBy(
  address operator,
  uint256 target,
  uint256 desired
) public view returns (uint256) {
  // read operator's permissions
  uint256 p = userRoles[operator];

  // taking into account operator's permissions,
  // 1) enable the permissions desired on the `target`
  target |= p & desired;
  // 2) disable the permissions desired on the `target`
  target &= FULL_PRIVILEGES_MASK ^ (p & (FULL_PRIVILEGES_MASK ^ desired));

  // return calculated result
  return target;
}

isFeatureEnabled keyboard_arrow_up

Parameters help

Name Type
required
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function isFeatureEnabled(uint256 required) public view returns (bool) {
  // delegate call to `__hasRole`, passing `features` property
  return __hasRole(features(), required);
}

isSenderInRole keyboard_arrow_up

Parameters help

Name Type
required
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function isSenderInRole(uint256 required) public view returns (bool) {
  // delegate call to `isOperatorInRole`, passing transaction sender
  return isOperatorInRole(msg.sender, required);
}

isOperatorInRole keyboard_arrow_up

Parameters help

Name Type
operator
address help
required
uint256 help

Properties

Visibility help public
Mutability help view
Source Code
function isOperatorInRole(address operator, uint256 required)
  public
  view
  returns (bool)
{
  // delegate call to `__hasRole`, passing operator's permissions (role)
  return __hasRole(userRoles[operator], required);
}

Parameters help

Name Type
_owner
address help

Properties

Visibility help public
Mutability help view
Source Code
function balanceOf(address _owner) public view returns (uint256 balance) {
  // read the balance and return
  return tokenBalances[_owner];
}

Parameters help

Name Type
_to
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function transfer(address _to, uint256 _value) public returns (bool success) {
  // just delegate call to `transferFrom`,
  // `FEATURE_TRANSFERS` is verified inside it
  return transferFrom(msg.sender, _to, _value);
}

Parameters help

Name Type
_from
address help
_to
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function transferFrom(
  address _from,
  address _to,
  uint256 _value
) public returns (bool success) {
  // depending on `FEATURE_UNSAFE_TRANSFERS` we execute either safe (default)
  // or unsafe transfer
  // if `FEATURE_UNSAFE_TRANSFERS` is enabled
  // or receiver has `ROLE_ERC20_RECEIVER` permission
  // or sender has `ROLE_ERC20_SENDER` permission
  if (
    isFeatureEnabled(FEATURE_UNSAFE_TRANSFERS) ||
    isOperatorInRole(_to, ROLE_ERC20_RECEIVER) ||
    isSenderInRole(ROLE_ERC20_SENDER)
  ) {
    // we execute unsafe transfer - delegate call to `unsafeTransferFrom`,
    // `FEATURE_TRANSFERS` is verified inside it
    unsafeTransferFrom(_from, _to, _value);
  }
  // otherwise - if `FEATURE_UNSAFE_TRANSFERS` is disabled
  // and receiver doesn't have `ROLE_ERC20_RECEIVER` permission
  else {
    // we execute safe transfer - delegate call to `safeTransferFrom`, passing empty `_data`,
    // `FEATURE_TRANSFERS` is verified inside it
    safeTransferFrom(_from, _to, _value, "");
  }

  // both `unsafeTransferFrom` and `safeTransferFrom` throw on any error, so
  // if we're here - it means operation successful,
  // just return true
  return true;
}

safeTransferFrom keyboard_arrow_up

Parameters help

Name Type
_from
address help
_to
address help
_value
uint256 help
_data
bytes help

Properties

Visibility help public
Mutability help transaction

Requirements help

Source Code
function safeTransferFrom(
  address _from,
  address _to,
  uint256 _value,
  bytes memory _data
) public {
  // first delegate call to `unsafeTransferFrom`
  // to perform the unsafe token(s) transfer
  unsafeTransferFrom(_from, _to, _value);

  // after the successful transfer - check if receiver supports
  // ERC20Receiver and execute a callback handler `onERC20Received`,
  // reverting whole transaction on any error:
  // check if receiver `_to` supports ERC20Receiver interface
  if (AddressUtils.isContract(_to)) {
    // if `_to` is a contract - execute onERC20Received
    bytes4 response = ERC20Receiver(_to).onERC20Received(
      msg.sender,
      _from,
      _value,
      _data
    );

    // expected response is ERC20_RECEIVED
    require(response == ERC20_RECEIVED, "invalid onERC20Received response");
  }
}

unsafeTransferFrom keyboard_arrow_up

Parameters help

Name Type
_from
address help
_to
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction

Requirements help

Source Code
function unsafeTransferFrom(
  address _from,
  address _to,
  uint256 _value
) public {
  // if `_from` is equal to sender, require transfers feature to be enabled
  // otherwise require transfers on behalf feature to be enabled
  require(
    (_from == msg.sender && isFeatureEnabled(FEATURE_TRANSFERS)) ||
      (_from != msg.sender && isFeatureEnabled(FEATURE_TRANSFERS_ON_BEHALF)),
    _from == msg.sender
      ? "transfers are disabled"
      : "transfers on behalf are disabled"
  );

  // non-zero source address check - Zeppelin
  // obviously, zero source address is a client mistake
  // it's not part of ERC20 standard but it's reasonable to fail fast
  // since for zero value transfer transaction succeeds otherwise
  require(_from != address(0), "ERC20: transfer from the zero address"); // Zeppelin msg

  // non-zero recipient address check
  require(_to != address(0), "ERC20: transfer to the zero address"); // Zeppelin msg

  // sender and recipient cannot be the same
  require(_from != _to, "sender and recipient are the same (_from = _to)");

  // sending tokens to the token smart contract itself is a client mistake
  require(
    _to != address(this),
    "invalid recipient (transfer to the token smart contract itself)"
  );

  // according to ERC-20 Token Standard, https://eips.ethereum.org/EIPS/eip-20
  // "Transfers of 0 values MUST be treated as normal transfers and fire the Transfer event."
  if (_value == 0) {
    // emit an ERC20 transfer event
    emit Transfer(_from, _to, _value);

    // don't forget to return - we're done
    return;
  }

  // no need to make arithmetic overflow check on the _value - by design of mint()

  // in case of transfer on behalf
  if (_from != msg.sender) {
    // read allowance value - the amount of tokens allowed to transfer - into the stack
    uint256 _allowance = transferAllowances[_from][msg.sender];

    // verify sender has an allowance to transfer amount of tokens requested
    require(_allowance >= _value, "ERC20: transfer amount exceeds allowance"); // Zeppelin msg

    // update allowance value on the stack
    _allowance -= _value;

    // update the allowance value in storage
    transferAllowances[_from][msg.sender] = _allowance;

    // emit an improved atomic approve event
    emit Approved(_from, msg.sender, _allowance + _value, _allowance);

    // emit an ERC20 approval event to reflect the decrease
    emit Approval(_from, msg.sender, _allowance);
  }

  // verify sender has enough tokens to transfer on behalf
  require(
    tokenBalances[_from] >= _value,
    "ERC20: transfer amount exceeds balance"
  ); // Zeppelin msg

  // perform the transfer:
  // decrease token owner (sender) balance
  tokenBalances[_from] -= _value;

  // increase `_to` address (receiver) balance
  tokenBalances[_to] += _value;

  // move voting power associated with the tokens transferred
  __moveVotingPower(votingDelegates[_from], votingDelegates[_to], _value);

  // emit an improved transfer event
  emit Transferred(msg.sender, _from, _to, _value);

  // emit an ERC20 transfer event
  emit Transfer(_from, _to, _value);
}

Parameters help

Name Type
_spender
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction

Requirements help

Source Code
function approve(address _spender, uint256 _value)
  public
  returns (bool success)
{
  // non-zero spender address check - Zeppelin
  // obviously, zero spender address is a client mistake
  // it's not part of ERC20 standard but it's reasonable to fail fast
  require(_spender != address(0), "ERC20: approve to the zero address"); // Zeppelin msg

  // read old approval value to emmit an improved event (ISBN:978-1-7281-3027-9)
  uint256 _oldValue = transferAllowances[msg.sender][_spender];

  // perform an operation: write value requested into the storage
  transferAllowances[msg.sender][_spender] = _value;

  // emit an improved atomic approve event (ISBN:978-1-7281-3027-9)
  emit Approved(msg.sender, _spender, _oldValue, _value);

  // emit an ERC20 approval event
  emit Approval(msg.sender, _spender, _value);

  // operation successful, return true
  return true;
}

Parameters help

Name Type
_owner
address help
_spender
address help

Properties

Visibility help public
Mutability help view
Source Code
function allowance(address _owner, address _spender)
  public
  view
  returns (uint256 remaining)
{
  // read the value from storage and return
  return transferAllowances[_owner][_spender];
}

Parameters help

Name Type
_spender
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function increaseAllowance(address _spender, uint256 _value)
  public
  virtual
  returns (bool)
{
  // read current allowance value
  uint256 currentVal = transferAllowances[msg.sender][_spender];

  // non-zero _value and arithmetic overflow check on the allowance
  require(
    currentVal + _value > currentVal,
    "zero value approval increase or arithmetic overflow"
  );

  // delegate call to `approve` with the new value
  return approve(_spender, currentVal + _value);
}

Parameters help

Name Type
_spender
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function decreaseAllowance(address _spender, uint256 _value)
  public
  virtual
  returns (bool)
{
  // read current allowance value
  uint256 currentVal = transferAllowances[msg.sender][_spender];

  // non-zero _value check on the allowance
  require(_value > 0, "zero value approval decrease");

  // verify allowance decrease doesn't underflow
  require(currentVal >= _value, "ERC20: decreased allowance below zero");

  // delegate call to `approve` with the new value
  return approve(_spender, currentVal - _value);
}

mint keyboard_arrow_up

Parameters help

Name Type
_to
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function mint(address _to, uint256 _value) public {
  // check if caller has sufficient permissions to mint tokens
  require(
    isSenderInRole(ROLE_TOKEN_CREATOR),
    "insufficient privileges (ROLE_TOKEN_CREATOR required)"
  );

  // non-zero recipient address check
  require(_to != address(0), "ERC20: mint to the zero address"); // Zeppelin msg

  // non-zero _value and arithmetic overflow check on the total supply
  // this check automatically secures arithmetic overflow on the individual balance
  require(
    totalSupply + _value > totalSupply,
    "zero value mint or arithmetic overflow"
  );

  // uint192 overflow check (required by voting delegation)
  require(
    totalSupply + _value <= type(uint192).max,
    "total supply overflow (uint192)"
  );

  // perform mint:
  // increase total amount of tokens value
  totalSupply += _value;

  // increase `_to` address balance
  tokenBalances[_to] += _value;

  // create voting power associated with the tokens minted
  __moveVotingPower(address(0), votingDelegates[_to], _value);

  // fire a minted event
  emit Minted(msg.sender, _to, _value);

  // emit an improved transfer event
  emit Transferred(msg.sender, address(0), _to, _value);

  // fire ERC20 compliant transfer event
  emit Transfer(address(0), _to, _value);
}

burn keyboard_arrow_up

Parameters help

Name Type
_from
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function burn(address _from, uint256 _value) public {
  // check if caller has sufficient permissions to burn tokens
  // and if not - check for possibility to burn own tokens or to burn on behalf
  if (!isSenderInRole(ROLE_TOKEN_DESTROYER)) {
    // if `_from` is equal to sender, require own burns feature to be enabled
    // otherwise require burns on behalf feature to be enabled
    require(
      (_from == msg.sender && isFeatureEnabled(FEATURE_OWN_BURNS)) ||
        (_from != msg.sender && isFeatureEnabled(FEATURE_BURNS_ON_BEHALF)),
      _from == msg.sender
        ? "burns are disabled"
        : "burns on behalf are disabled"
    );

    // in case of burn on behalf
    if (_from != msg.sender) {
      // read allowance value - the amount of tokens allowed to be burnt - into the stack
      uint256 _allowance = transferAllowances[_from][msg.sender];

      // verify sender has an allowance to burn amount of tokens requested
      require(_allowance >= _value, "ERC20: burn amount exceeds allowance"); // Zeppelin msg

      // update allowance value on the stack
      _allowance -= _value;

      // update the allowance value in storage
      transferAllowances[_from][msg.sender] = _allowance;

      // emit an improved atomic approve event
      emit Approved(msg.sender, _from, _allowance + _value, _allowance);

      // emit an ERC20 approval event to reflect the decrease
      emit Approval(_from, msg.sender, _allowance);
    }
  }

  // at this point we know that either sender is ROLE_TOKEN_DESTROYER or
  // we burn own tokens or on behalf (in latest case we already checked and updated allowances)
  // we have left to execute balance checks and burning logic itself

  // non-zero burn value check
  require(_value != 0, "zero value burn");

  // non-zero source address check - Zeppelin
  require(_from != address(0), "ERC20: burn from the zero address"); // Zeppelin msg

  // verify `_from` address has enough tokens to destroy
  // (basically this is a arithmetic overflow check)
  require(tokenBalances[_from] >= _value, "ERC20: burn amount exceeds balance"); // Zeppelin msg

  // perform burn:
  // decrease `_from` address balance
  tokenBalances[_from] -= _value;

  // decrease total amount of tokens value
  totalSupply -= _value;

  // destroy voting power associated with the tokens burnt
  __moveVotingPower(votingDelegates[_from], address(0), _value);

  // fire a burnt event
  emit Burnt(msg.sender, _from, _value);

  // emit an improved transfer event
  emit Transferred(msg.sender, _from, address(0), _value);

  // fire ERC20 compliant transfer event
  emit Transfer(_from, address(0), _value);
}

getVotingPower keyboard_arrow_up

Parameters help

Name Type
_of
address help

Properties

Visibility help public
Mutability help view
Source Code
function getVotingPower(address _of) public view returns (uint256) {
  // get a link to an array of voting power history records for an address specified
  VotingPowerRecord[] storage history = votingPowerHistory[_of];

  // lookup the history and return latest element
  return history.length == 0 ? 0 : history[history.length - 1].votingPower;
}

getVotingPowerAt keyboard_arrow_up

Parameters help

Name Type
_of
address help
_blockNum
uint256 help

Properties

Visibility help public
Mutability help view

Requirements help

Source Code
function getVotingPowerAt(address _of, uint256 _blockNum)
  public
  view
  returns (uint256)
{
  // make sure block number is not in the past (not the finalized block)
  require(_blockNum < block.number, "not yet determined"); // Compound msg

  // get a link to an array of voting power history records for an address specified
  VotingPowerRecord[] storage history = votingPowerHistory[_of];

  // if voting power history for the account provided is empty
  if (history.length == 0) {
    // than voting power is zero - return the result
    return 0;
  }

  // check latest voting power history record block number:
  // if history was not updated after the block of interest
  if (history[history.length - 1].blockNumber <= _blockNum) {
    // we're done - return last voting power record
    return getVotingPower(_of);
  }

  // check first voting power history record block number:
  // if history was never updated before the block of interest
  if (history[0].blockNumber > _blockNum) {
    // we're done - voting power at the block num of interest was zero
    return 0;
  }

  // `votingPowerHistory[_of]` is an array ordered by `blockNumber`, ascending;
  // apply binary search on `votingPowerHistory[_of]` to find such an entry number `i`, that
  // `votingPowerHistory[_of][i].blockNumber <= _blockNum`, but in the same time
  // `votingPowerHistory[_of][i + 1].blockNumber > _blockNum`
  // return the result - voting power found at index `i`
  return history[__binaryLookup(_of, _blockNum)].votingPower;
}

getVotingPowerHistory keyboard_arrow_up

Parameters help

Name Type
_of
address help

Properties

Visibility help public
Mutability help view
Source Code
function getVotingPowerHistory(address _of)
  public
  view
  returns (VotingPowerRecord[] memory)
{
  // return an entire array as memory
  return votingPowerHistory[_of];
}

getVotingPowerHistoryLength keyboard_arrow_up

Parameters help

Name Type
_of
address help

Properties

Visibility help public
Mutability help view
Source Code
function getVotingPowerHistoryLength(address _of)
  public
  view
  returns (uint256)
{
  // read array length and return
  return votingPowerHistory[_of].length;
}

delegate keyboard_arrow_up

Parameters help

Name Type
_to
address help

Properties

Visibility help public
Mutability help transaction

Requirements help

null
Source Code
function delegate(address _to) public {
  // verify delegations are enabled
  require(isFeatureEnabled(FEATURE_DELEGATIONS), "delegations are disabled");
  // delegate call to `__delegate`
  __delegate(msg.sender, _to);
}

delegateWithSig keyboard_arrow_up

Parameters help

Name Type
_to
address help
_nonce
uint256 help
_exp
uint256 help
v
uint8 help
r
bytes32 help
s
bytes32 help

Properties

Visibility help public
Mutability help transaction
Source Code
function delegateWithSig(
  address _to,
  uint256 _nonce,
  uint256 _exp,
  uint8 v,
  bytes32 r,
  bytes32 s
) public {
  // verify delegations on behalf are enabled
  require(
    isFeatureEnabled(FEATURE_DELEGATIONS_ON_BEHALF),
    "delegations on behalf are disabled"
  );

  // build the EIP-712 contract domain separator
  bytes32 domainSeparator = keccak256(
    abi.encode(
      DOMAIN_TYPEHASH,
      keccak256(bytes(name)),
      block.chainid,
      address(this)
    )
  );

  // build the EIP-712 hashStruct of the delegation message
  bytes32 hashStruct = keccak256(
    abi.encode(DELEGATION_TYPEHASH, _to, _nonce, _exp)
  );

  // calculate the EIP-712 digest "\x19\x01" ‖ domainSeparator ‖ hashStruct(message)
  bytes32 digest = keccak256(
    abi.encodePacked("\x19\x01", domainSeparator, hashStruct)
  );

  // recover the address who signed the message with v, r, s
  address signer = ecrecover(digest, v, r, s);

  // perform message integrity and security validations
  require(signer != address(0), "invalid signature"); // Compound msg
  require(_nonce == nonces[signer], "invalid nonce"); // Compound msg
  require(block.timestamp < _exp, "signature expired"); // Compound msg

  // update the nonce for that particular signer to avoid replay attack
  nonces[signer]++;

  // delegate call to `__delegate` - execute the logic required
  __delegate(signer, _to);
}

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 IlluviumERC20.__delegate keyboard_arrow_up

Parameters help

Name Type
_from
address help
_to
address help

Properties

Visibility help private
Mutability help transaction
Source Code
function __delegate(address _from, address _to) private {
  // read current delegate to be replaced by a new one
  address _fromDelegate = votingDelegates[_from];

  // read current voting power (it is equal to token balance)
  uint256 _value = tokenBalances[_from];

  // reassign voting delegate to `_to`
  votingDelegates[_from] = _to;

  // update voting power for `_fromDelegate` and `_to`
  __moveVotingPower(_fromDelegate, _to, _value);

  // emit an event
  emit DelegateChanged(_from, _fromDelegate, _to);
}

internal IlluviumERC20.__moveVotingPower keyboard_arrow_up

Parameters help

Name Type
_from
address help
_to
address help
_value
uint256 help

Properties

Visibility help private
Mutability help transaction
Source Code
function __moveVotingPower(
  address _from,
  address _to,
  uint256 _value
) private {
  // if there is no move (`_from == _to`) or there is nothing to move (`_value == 0`)
  if (_from == _to || _value == 0) {
    // return silently with no action
    return;
  }

  // if source address is not zero - decrease its voting power
  if (_from != address(0)) {
    // read current source address voting power
    uint256 _fromVal = getVotingPower(_from);

    // calculate decreased voting power
    // underflow is not possible by design:
    // voting power is limited by token balance which is checked by the callee
    uint256 _toVal = _fromVal - _value;

    // update source voting power from `_fromVal` to `_toVal`
    __updateVotingPower(_from, _fromVal, _toVal);
  }

  // if destination address is not zero - increase its voting power
  if (_to != address(0)) {
    // read current destination address voting power
    uint256 _fromVal = getVotingPower(_to);

    // calculate increased voting power
    // overflow is not possible by design:
    // max token supply limits the cumulative voting power
    uint256 _toVal = _fromVal + _value;

    // update destination voting power from `_fromVal` to `_toVal`
    __updateVotingPower(_to, _fromVal, _toVal);
  }
}

internal IlluviumERC20.__updateVotingPower keyboard_arrow_up

Parameters help

Name Type
_of
address help
_fromVal
uint256 help
_toVal
uint256 help

Properties

Visibility help private
Mutability help transaction
Source Code
function __updateVotingPower(
  address _of,
  uint256 _fromVal,
  uint256 _toVal
) private {
  // get a link to an array of voting power history records for an address specified
  VotingPowerRecord[] storage history = votingPowerHistory[_of];

  // if there is an existing voting power value stored for current block
  if (
    history.length != 0 &&
    history[history.length - 1].blockNumber == block.number
  ) {
    // update voting power which is already stored in the current block
    history[history.length - 1].votingPower = uint192(_toVal);
  }
  // otherwise - if there is no value stored for current block
  else {
    // add new element into array representing the value for current block
    history.push(VotingPowerRecord(uint64(block.number), uint192(_toVal)));
  }

  // emit an event
  emit VotingPowerChanged(_of, _fromVal, _toVal);
}

internal IlluviumERC20.__binaryLookup keyboard_arrow_up

Parameters help

Name Type
_to
address help
n
uint256 help

Properties

Visibility help private
Mutability help view
Source Code
function __binaryLookup(address _to, uint256 n) private view returns (uint256) {
  // get a link to an array of voting power history records for an address specified
  VotingPowerRecord[] storage history = votingPowerHistory[_to];

  // left bound of the search interval, originally start of the array
  uint256 i = 0;

  // right bound of the search interval, originally end of the array
  uint256 j = history.length - 1;

  // the iteration process narrows down the bounds by
  // splitting the interval in a half oce per each iteration
  while (j > i) {
    // get an index in the middle of the interval [i, j]
    uint256 k = j - (j - i) / 2;

    // read an element to compare it with the value of interest
    VotingPowerRecord memory cp = history[k];

    // if we've got a strict equal - we're lucky and done
    if (cp.blockNumber == n) {
      // just return the result - index `k`
      return k;
    }
    // if the value of interest is bigger - move left bound to the middle
    else if (cp.blockNumber < n) {
      // move left bound `i` to the middle position `k`
      i = k;
    }
    // otherwise, when the value of interest is smaller - move right bound to the middle
    else {
      // move right bound `j` to the middle position `k - 1`:
      // element at position `k` is bigger and cannot be the result
      j = k - 1;
    }
  }

  // reaching that point means no exact match found
  // since we're interested in the element which is not bigger than the
  // element of interest, we return the lower bound `i`
  return i;
}

internal AccessControl.__hasRole keyboard_arrow_up

Parameters help

Name Type
actual
uint256 help
required
uint256 help

Properties

Visibility help internal
Mutability help pure
Source Code
function __hasRole(uint256 actual, uint256 required)
  internal
  pure
  returns (bool)
{
  // check the bitmask for the role required and return the result
  return actual & required == required;
}