yLeaf Token & Presale Audit

Summary

SourceHat Smart Contract Audits Deflationary Token Smart Contract yLEAF is a new deflationary token. Its a new breed of experimental protocols based and adopting some famous project in the past. Performing a 3% deflationary burn on every transaction will make the supply scarce. The presale will be announced on the team's medium.

For this audit, we inspected yLEAF's token and presale contracts.

The contract includes all the standard ERC20 functions as defined in the ERC20 protocol by the Ethereum Foundation.

Additional features included in the contracts:
  • No minting occurs after deployment - the total supply shall only decrease.
  • Burn tokens to reduce the total/circulating supply.
  • Ownership - Some functions are protected and can only be called by the contract owner. You can transfer ownership to any address.
  • Tokens purchased with Ether are sent directly to the purchaser's address.
  • Utilization of SafeMath to prevent overflows.
Audit Findings Summary
  • No security issues were identified.
  • Date: November 22nd, 2020.

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesN/APASS
Deprecated OpcodesN/APASS
Ether ThiefN/APASS
ExceptionsN/APASS
External CallsN/APASS
Integer Over/UnderflowN/APASS
Multiple SendsN/APASS
SuicideN/APASS
State Change External CallsN/APass
Unchecked RetvalN/APASS
User Supplied AssertionA user can trigger an assertion violation on the slash()
function, but their transaction will revert safely. This poses no security risk.
Warning
Critical Solidity CompilerN/APASS
Overall Contract Safety PASS

Token Contract


Token Graph

Multi-file Token


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Lib] SafeMath 
    - [Int] mul
    - [Int] div
    - [Int] sub
    - [Int] add
    - [Int] ceil

 +  yLEAF 
    - [Pub]  #
    - [Pub] name
    - [Pub] symbol
    - [Pub] decimals
    - [Pub] totalSupply
    - [Pub] balanceOf
    - [Pub] allowance
    - [Pub] slash
    - [Pub] transfer #
    - [Pub] increaseAllowance #
    - [Pub] decreaseAllowance #
    - [Int] _transfer #
    - [Pub] approve #
    - [Pub] transferFrom #
    - [Int] _issue #
    - [Ext] burn #
    - [Int] _burn #
    - [Ext] burnFrom #
    - [Int] _mint #
    - [Ext]  ($)
    - [Ext]  ($)
							

Click here to download the source code as a .sol file.


//SPDX-License-Identifier: MIT

/*##################################################
* #################  yLEAF  ########################
* ############ Deflationary  Token #################
* ##################################################
*
* ##################################################
* #### Every Token transfer initiates a 3% Burn ####
* #### of the amount sent in each transaction.  ####
* ##################################################
*
* ##################################################
* ############### 20 November 2020 ################
* ##################################################
**/
pragma solidity 0.7.5;

library SafeMath { //Safe Maths
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a / b;
    return c;
  }
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
  function ceil(uint256 a, uint256 m) internal pure returns (uint256) {
    uint256 c = add(a,m);
    uint256 d = sub(c,1);
    return mul(div(d,m),m);
  }
}

contract yLEAF {
  using SafeMath for uint256;
  mapping (address => uint256) private _balances;
  mapping (address => mapping (address => uint256)) private _allowed;
  string constant _name = "yLEAF";
  string constant _symbol = "yLEAF";
  uint8  constant _decimals = 18;
  uint256 private _totalSupply = 2000000000000000000000;
  uint256 constant basePercent = 300;
  address private ownerAddress = 0x5652F50Db5B7a3E753Db5c1730c7460936BE67Ce;
  address private presaleContract = 0xA74855652777aFB6Cf8b10a44c85d687b1D19d28;
  event Transfer(address indexed from, address indexed to, uint256 value);
  event Approval(address indexed owner, address indexed spender, uint256 value);
  constructor() {
    _issue(ownerAddress, 500000000000000000000);
    _issue(presaleContract, 1500000000000000000000);
  }
  function name() public pure returns(string memory) {
    return _name;
  }
  function symbol() public pure returns(string memory) {
    return _symbol;
  }
  function decimals() public pure returns(uint8) {
    return _decimals;
  }
  function totalSupply() public view returns (uint256) {
    return _totalSupply;
  }
  function balanceOf(address owner) public view returns (uint256) {
    return _balances[owner];
  }
  function allowance(address owner, address spender) public view returns (uint256) {
    return _allowed[owner][spender];
  }
  function slash(uint256 value) public pure returns (uint256)  {
    uint256 roundValue = value.ceil(basePercent);
    uint256 slashValue = roundValue.mul(basePercent).div(10000); //Burn
    return slashValue;
  }
  function transfer(address to, uint256 value) public returns (bool) {
    require(value <= _balances[msg.sender]);
    uint256 tokensToBurn = slash(value);  // Burn on transfer
    uint256 tokensToTransfer = value.sub(tokensToBurn);
    _balances[msg.sender] = _balances[msg.sender].sub(value);
    _balances[to] = _balances[to].add(tokensToTransfer);
    _totalSupply = _totalSupply.sub(tokensToBurn);
    emit Transfer(msg.sender, to, tokensToTransfer);
    emit Transfer(msg.sender, address(0), tokensToBurn);
    return true;
  }
  function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
    require(spender != address(0));
    _allowed[msg.sender][spender] = (
    _allowed[msg.sender][spender].add(addedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }
  function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
    require(spender != address(0));
    _allowed[msg.sender][spender] = (
    _allowed[msg.sender][spender].sub(subtractedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }
  function _transfer(address from, address to, uint256 value) internal {
    _balances[from] = _balances[from].sub(value);
    _balances[to] = _balances[to].add(value);
    emit Transfer(from, to, value);
  }
  function approve(address spender, uint256 value) public returns (bool) {
    require(spender != address(0));
    _allowed[msg.sender][spender] = value;
    emit Approval(msg.sender, spender, value);
    return true;
  }
  function transferFrom(address from, address to, uint256 value) public returns (bool) {
    require(value <= _balances[from]);
    require(value <= _allowed[from][msg.sender]);
    require(to != address(0));
    _balances[from] = _balances[from].sub(value);
    uint256 tokensToBurn = slash(value);  //Burn on transfer
    uint256 tokensToTransfer = value.sub(tokensToBurn);
    _balances[to] = _balances[to].add(tokensToTransfer);
    _totalSupply = _totalSupply.sub(tokensToBurn);
    _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
    emit Transfer(from, to, tokensToTransfer);
    emit Transfer(from, address(0), tokensToBurn);
    return true;
  }
  function _issue(address account, uint256 amount) internal {
    require(amount != 0);
    _balances[account] = _balances[account].add(amount);
    emit Transfer(address(0), account, amount);
  }
  function burn(uint256 amount) external {
    _burn(msg.sender, amount);
  }
  function _burn(address account, uint256 amount) internal {
    require(amount != 0);
    require(amount <= _balances[account]);
    _totalSupply = _totalSupply.sub(amount);
    _balances[account] = _balances[account].sub(amount);
    emit Transfer(account, address(0), amount);
  }
  function burnFrom(address account, uint256 amount) external {
    require(amount <= _allowed[account][msg.sender]);
    _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(amount);
    _burn(account, amount);
  }
  function _mint(address account, uint256 value) internal {
    _balances[account] = _balances[account].add(value);
    emit Transfer(address(0), account, value);
  }
  fallback() external payable {
      revert();
  }
  receive() external payable {
      revert();
  }
}


PreSale Contract


Contract Graph

Multi-file Token


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Lib] SafeMath 
    - [Int] mul
    - [Int] add

 +  Ownable 
    - [Pub]  #
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 +  yLEAFsale (Ownable)
    - [Pub]  #
    - [Pub] startSale #
       - modifiers: onlyOwner
    - [Pub] isActive
    - [Pub] goalReached
    - [Ext]  ($)
    - [Ext]  ($)
    - [Pub] buyTokens ($)
       - modifiers: whenSaleIsActive
    - [Pub] tokensAvailable
    - [Pub] endSale #
       - modifiers: onlyOwner
	   
							

Click here to download the source code as a .sol file.


//SPDX-License-Identifier: MIT

/*##################################################
* ############  yLEAF Token Sale  ##################
* ##################################################
*
* ##################################################
* ############# 20 November 2020 ###################
* ##################################################
**/

pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.7.5;
library SafeMath {
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}
contract Ownable {
  address public owner;
  address payable public ownerPayable;
  constructor()  {
    owner = address(msg.sender);
    ownerPayable = address(uint160(owner));
  }
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    owner = newOwner;
    ownerPayable = address(uint160(owner));

  }
}
contract yLEAFsale is Ownable {
  using SafeMath for uint256;
  IERC20 token;
  string public constant Info = "This is the official Presale contract for yLEAF";
  uint256 public constant RATE = 7; //number of tokens per ether
  uint256 public constant CAP = 200;  //Number of ether accepted until the sale ends
  bool private initialized = false; //We dont start until you call startSale()
  uint256 public raisedAmount = 0; //allow users to read the amount of funds raised
  modifier whenSaleIsActive() {
    // Check if sale is active
    assert(isActive());
    _;
  }
  constructor() {}

  function startSale(address _tokenAddr) public onlyOwner {
      require(initialized == false); //Call when you are ready to start the sale
      token = IERC20(_tokenAddr);
      token.approve(address(this), 115792089237316195423570985008687907853269984665640564039457584007913129639935);
      initialized = true;
  }
  function isActive() public view returns (bool) {
    return (
        initialized == true //Lets the public know if we're live
    );
  }
  function goalReached() public view returns (bool) {
    return (raisedAmount >= CAP * 1 ether);
  }
  fallback() external payable {
    buyTokens();
  } //Fallbacks so if someone sends ether directly to the contract it will function as a purchase
  receive() external payable {
    buyTokens();
  }
  function buyTokens() public payable whenSaleIsActive {
    require(msg.value >= 0.5 ether);
    require(msg.value <= 2 ether);
    uint256 weiAmount = msg.value;
    uint256 tokens = weiAmount.mul(RATE);
    raisedAmount = raisedAmount.add(msg.value);
    ownerPayable.transfer(msg.value);
    token.transferFrom(address(this), msg.sender, tokens);
  }
  function tokensAvailable() public view returns (uint256) {
    return token.balanceOf(address(this));
  }
  function endSale() onlyOwner public {
    uint256 tokenBalance = token.balanceOf(address(this));
    token.transferFrom(address(this), owner, tokenBalance); //Tokens returned to owner wallet
    selfdestruct(ownerPayable);
  }
}