Blockwell

Modum Token

ERC20

This contract is an ERC20 token.

Name Modum Token
Symbol MOD
Decimals 0
Total Supply 21,266,200 MOD

About

Stats

Public Functions 21
Event Types 4
Code Size 19,367 bytes

Library Use

Uses SafeMath for uint256.

Events (4) keyboard_arrow_up

Approval Event

Parameters help
owner
address help
spender
address help
value
uint256 help

Payout Event

Parameters help
weiPerToken
uint256 help

Transfer Event

Parameters help
from
address help
to
address help
value
uint256 help

Voted Event

Parameters help
_addr
address help
option
bool help
votes
uint256 help

Account Struct

Members
lastProposalStartTime
uint256 help
lastAirdropWei
uint256 help
lastAirdropClaimTime
uint256 help
bonusWei
uint256 help
valueModVote
uint256 help
valueMod
uint256 help

Proposal Struct

Members
addr
string help
hash
bytes32 help
valueMod
uint256 help
startTime
uint256 help
yay
uint256 help
nay
uint256 help

maxTokens Constant

uint256 help
30 * 1000 * 1000

redistributionTimeout Constant

uint256 help
548 days

name Constant

string help
Modum Token

symbol Constant

string help
MOD

decimals Constant

uint8 help
0

votingDuration Constant

uint256 help
2 weeks

blockingDuration Constant

uint256 help
90 days

owner Variable

address help

totalDropPerUnlockedToken Variable

uint256 help

rounding Variable

uint256 help

lockedTokens Variable

uint256 help

mintDone Variable

bool help

currentProposal Variable

Proposal help

lastNegativeVoting Variable

uint256 help

totalSupply Variable

uint256 help

allowed Variable

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

accounts Variable

mapping(address => Account) help
Internal Variable

Functions Expand All Collapse All

Parameters help

Name Type
_owner
address help

Properties

Visibility help public
Mutability help constant
Source Code
function balanceOf(address _owner) public constant returns (uint256 balance) {
  return accounts[_owner].valueMod;
}

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) {
  require(mintDone);
  require(_value > 0);
  Account memory tmpFrom = accounts[msg.sender];
  require(tmpFrom.valueMod >= _value);

  Account storage from = updateAccount(msg.sender, UpdateMode.Both);
  Account storage to = updateAccount(_to, UpdateMode.Both);
  from.valueMod = from.valueMod.sub(_value);
  to.valueMod = to.valueMod.add(_value);
  Transfer(msg.sender, _to, _value);
  return true;
}

Parameters help

Name Type
_owner
address help
_spender
address help

Properties

Visibility help public
Mutability help constant
Source Code
function allowance(address _owner, address _spender)
  public
  constant
  returns (uint256 remaining)
{
  return allowed[_owner][_spender];
}

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) {
  require(mintDone);
  require(_value > 0);
  Account memory tmpFrom = accounts[_from];
  require(tmpFrom.valueMod >= _value);
  require(allowed[_from][msg.sender] >= _value);

  Account storage from = updateAccount(_from, UpdateMode.Both);
  Account storage to = updateAccount(_to, UpdateMode.Both);
  from.valueMod = from.valueMod.sub(_value);
  to.valueMod = to.valueMod.add(_value);
  allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
  Transfer(msg.sender, _to, _value);
  return true;
}

Parameters help

Name Type
_spender
address help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction

Requirements help

One or more of the following:
Source Code
function approve(address _spender, uint256 _value) public returns (bool) {
  // To change the approve amount you first have to reduce the addresses`
  //  allowance to zero by calling `approve(_spender, 0)` if it is not
  //  already 0 to mitigate the race condition described here:
  //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
  require((_value == 0) || (allowed[msg.sender][_spender] == 0));

  allowed[msg.sender][_spender] = _value;
  Approval(msg.sender, _spender, _value);
  return true;
}

transferOwnership keyboard_arrow_up

Parameters help

Name Type
_newOwner
address help

Properties

Visibility help public
Mutability help transaction
Source Code
function transferOwnership(address _newOwner) public {
  require(msg.sender == owner);
  require(_newOwner != address(0));
  owner = _newOwner;
}

votingProposal keyboard_arrow_up

Parameters help

Name Type
_addr
string help
_hash
bytes32 help
_value
uint256 help

Properties

Visibility help public
Mutability help transaction

Requirements help

Source Code
function votingProposal(
  string _addr,
  bytes32 _hash,
  uint256 _value
) public {
  require(msg.sender == owner); // proposal ony by onwer
  require(!isProposalActive()); // no proposal is active, cannot vote in parallel
  require(_value <= lockedTokens); //proposal cannot be larger than remaining locked tokens
  require(_value > 0); //there needs to be locked tokens to make proposal, at least 1 locked token
  require(_hash != bytes32(0)); //hash need to be set
  require(bytes(_addr).length > 0); //the address need to be set and non-empty
  require(mintDone); //minting phase needs to be over
  //in case of negative vote, wait 90 days. If no lastNegativeVoting have
  //occured, lastNegativeVoting is 0 and now is always larger than 14.1.1970
  //(1.1.1970 plus blockingDuration).
  require(now >= lastNegativeVoting.add(blockingDuration));

  currentProposal = Proposal(_addr, _hash, _value, now, 0, 0);
}

vote keyboard_arrow_up

Parameters help

Name Type
_vote
bool help

Properties

Visibility help public
Mutability help transaction

Requirements help

Source Code
function vote(bool _vote) public returns (uint256) {
  require(isVoteOngoing()); // vote needs to be ongoing
  Account storage account = updateAccount(msg.sender, UpdateMode.Vote);
  uint256 votes = account.valueModVote; //available votes
  require(votes > 0); //voter must have a vote left, either by not voting yet, or have modum tokens

  if (_vote) {
    currentProposal.yay = currentProposal.yay.add(votes);
  } else {
    currentProposal.nay = currentProposal.nay.add(votes);
  }

  account.valueModVote = 0;
  Voted(msg.sender, _vote, votes);
  return votes;
}

showVotes keyboard_arrow_up

Parameters help

Name Type
_addr
address help

Properties

Visibility help public
Mutability help constant
Source Code
function showVotes(address _addr) public constant returns (uint256) {
  Account memory account = accounts[_addr];
  if (
    account.lastProposalStartTime < currentProposal.startTime || // the user did set his token power yet
    (account.lastProposalStartTime == 0 && currentProposal.startTime == 0)
  ) {
    return account.valueMod;
  }
  return account.valueModVote;
}

claimVotingProposal keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help transaction
Source Code
function claimVotingProposal() public {
  require(msg.sender == owner); //only owner can claim proposal
  require(isProposalActive()); // proposal active
  require(isVotingPhaseOver()); // voting has already ended

  if (
    currentProposal.yay > currentProposal.nay && currentProposal.valueMod > 0
  ) {
    //Vote was accepted
    Account storage account = updateAccount(owner, UpdateMode.Both);
    uint256 valueMod = currentProposal.valueMod;
    account.valueMod = account.valueMod.add(valueMod); //add tokens to owner
    totalSupply = totalSupply.add(valueMod);
    lockedTokens = lockedTokens.sub(valueMod);
  } else if (currentProposal.yay <= currentProposal.nay) {
    //in case of a negative vote, set the time of this negative
    //vote to the end of the negative voting period.
    //This will prevent any new voting to be conducted.
    lastNegativeVoting = currentProposal.startTime.add(votingDuration);
  }
  delete currentProposal; //proposal ended
}

isProposalActive keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help constant
Source Code
function isProposalActive() public constant returns (bool) {
  return currentProposal.hash != bytes32(0);
}

isVoteOngoing keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help constant
Source Code
function isVoteOngoing() public constant returns (bool) {
  return
    isProposalActive() &&
    now >= currentProposal.startTime &&
    now < currentProposal.startTime.add(votingDuration);
  //its safe to use it for longer periods:
  //https://ethereum.stackexchange.com/questions/6795/is-block-timestamp-safe-for-longer-time-periods
}

isVotingPhaseOver keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help constant
Source Code
function isVotingPhaseOver() public constant returns (bool) {
  //its safe to use it for longer periods:
  //https://ethereum.stackexchange.com/questions/6795/is-block-timestamp-safe-for-longer-time-periods
  return now >= currentProposal.startTime.add(votingDuration);
}

mint keyboard_arrow_up

Parameters help

Name Type
_recipient
address[] help
_value
uint256[] help

Properties

Visibility help public
Mutability help transaction
Source Code
function mint(address[] _recipient, uint256[] _value) public {
  require(msg.sender == owner); //only owner can claim proposal
  require(!mintDone); //only during minting
  //require(_recipient.length == _value.length); //input need to be of same size
  //we know what we are doing... remove check to save gas

  //we want to mint a couple of accounts
  for (uint8 i = 0; i < _recipient.length; i++) {
    //require(lockedTokens.add(totalSupply).add(_value[i]) <= maxTokens);
    //do the check in the mintDone

    //121 gas can be saved by creating temporary variables
    address tmpRecipient = _recipient[i];
    uint256 tmpValue = _value[i];

    //no need to update account, as we have not set minting to true. This means
    //nobody can start a proposal (isVoteOngoing() is always false) and airdrop
    //cannot be done either totalDropPerUnlockedToken is 0 thus, bonus is always
    //zero.
    Account storage account = accounts[tmpRecipient];
    account.valueMod = account.valueMod.add(tmpValue);
    //if this remains 0, we cannot calculate the time period when the user claimed
    //his airdrop, thus, set it to now
    account.lastAirdropClaimTime = now;
    totalSupply = totalSupply.add(tmpValue); //create the tokens and add to recipient
    Transfer(msg.sender, tmpRecipient, tmpValue);
  }
}

setMintDone keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help transaction
Source Code
function setMintDone() public {
  require(msg.sender == owner);
  require(!mintDone); //only in minting phase
  //here we check that we never exceed the 30mio max tokens. This includes
  //the locked and the unlocked tokens.
  require(lockedTokens.add(totalSupply) <= maxTokens);
  mintDone = true; //end the minting
}

constructor keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help payable
Source Code
function() public payable {
  require(mintDone); //minting needs to be over
  require(msg.sender == owner); //ETH payment need to be one-way only, from modum to tokenholders, confirmed by Lykke
  payout(msg.value);
}

payBonus keyboard_arrow_up

Parameters help

Name Type
_addr
address[] help

Properties

Visibility help public
Mutability help payable
Source Code
function payBonus(address[] _addr) public payable {
  require(msg.sender == owner); //ETH payment need to be one-way only, from modum to tokenholders, confirmed by Lykke
  uint256 totalWei = 0;
  for (uint8 i = 0; i < _addr.length; i++) {
    Account storage account = updateAccount(_addr[i], UpdateMode.Wei);
    if (now >= account.lastAirdropClaimTime + redistributionTimeout) {
      totalWei += account.bonusWei;
      account.bonusWei = 0;
      account.lastAirdropClaimTime = now;
    } else {
      revert();
    }
  }
  payout(msg.value.add(totalWei));
}

showBonus keyboard_arrow_up

Parameters help

Name Type
_addr
address help

Properties

Visibility help public
Mutability help constant
Source Code
function showBonus(address _addr) public constant returns (uint256) {
  uint256 bonus = totalDropPerUnlockedToken.sub(accounts[_addr].lastAirdropWei);
  if (bonus != 0) {
    return accounts[_addr].bonusWei.add(bonus.mul(accounts[_addr].valueMod));
  }
  return accounts[_addr].bonusWei;
}

claimBonus keyboard_arrow_up

Parameters help

This function has no parameters.

Properties

Visibility help public
Mutability help transaction

Requirements help

Source Code
function claimBonus() public returns (uint256) {
  require(mintDone); //minting needs to be over

  Account storage account = updateAccount(msg.sender, UpdateMode.Wei);
  uint256 sendValue = account.bonusWei; //fetch the values

  if (sendValue != 0) {
    account.bonusWei = 0; //set to zero (before, against reentry)
    account.lastAirdropClaimTime = now; //mark as collected now
    msg.sender.transfer(sendValue); //send the bonus to the correct account
    return sendValue;
  }
  return 0;
}

increaseApproval keyboard_arrow_up

Parameters help

Name Type
_spender
address help
_addedValue
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function increaseApproval(address _spender, uint256 _addedValue)
  public
  returns (bool success)
{
  allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(
    _addedValue
  );
  Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
  return true;
}

decreaseApproval keyboard_arrow_up

Parameters help

Name Type
_spender
address help
_subtractedValue
uint256 help

Properties

Visibility help public
Mutability help transaction
Source Code
function decreaseApproval(address _spender, uint256 _subtractedValue)
  public
  returns (bool success)
{
  uint256 oldValue = allowed[msg.sender][_spender];
  if (_subtractedValue > oldValue) {
    allowed[msg.sender][_spender] = 0;
  } else {
    allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
  }
  Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
  return true;
}

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 ModumToken.updateAccount keyboard_arrow_up

Parameters help

Name Type
_addr
address help
mode
UpdateMode help

Properties

Visibility help internal
Mutability help transaction
Source Code
function updateAccount(address _addr, UpdateMode mode)
  internal
  returns (Account storage)
{
  Account storage account = accounts[_addr];
  if (mode == UpdateMode.Vote || mode == UpdateMode.Both) {
    if (
      isVoteOngoing() &&
      account.lastProposalStartTime < currentProposal.startTime
    ) {
      // the user did set his token power yet
      account.valueModVote = account.valueMod;
      account.lastProposalStartTime = currentProposal.startTime;
    }
  }

  if (mode == UpdateMode.Wei || mode == UpdateMode.Both) {
    uint256 bonus = totalDropPerUnlockedToken.sub(account.lastAirdropWei);
    if (bonus != 0) {
      account.bonusWei = account.bonusWei.add(bonus.mul(account.valueMod));
      account.lastAirdropWei = totalDropPerUnlockedToken;
    }
  }

  return account;
}

internal ModumToken.payout keyboard_arrow_up

Parameters help

Name Type
valueWei
uint256 help

Properties

Visibility help internal
Mutability help transaction
Source Code
function payout(uint256 valueWei) internal {
  uint256 value = valueWei.add(rounding); //add old rounding
  rounding = value % totalSupply; //ensure no rounding error
  uint256 weiPerToken = value.sub(rounding).div(totalSupply);
  totalDropPerUnlockedToken = totalDropPerUnlockedToken.add(weiPerToken); //account for locked tokens and add the drop
  Payout(weiPerToken);
}