Overview

Tree Defi
Rank #N/A

Skynet Trust Score

79%
  • Project is Relatively Decentralized
  • Large Market Cap (top 25%)
  • Long-running Project
  • Trust Score is #1 amongst all projects
Security Score
79 / 100
Market & Community
72 / 100

Tree Defi Info

The Eco-Friendly Yield Farming community on BSC: We use swap fees to plant new trees around the globe.

Audits

Onboarded Date

13/Dec/2022

Contracts

0xf0f...cf77e

How do you feel about this project's security?
Documents
File Name Type Size Upload Date Action
Zip File 4.57 MB 12 Dec 2021
PDF File 8.89 MB 24 Nov 2021
MP4 File 14.62 MB 19 Nov 2021
XSL File 2.38 KB 14 Nov 2021
Floder File 87.24 MB 08 Nov 2021
PNG File 879 KB 02 Nov 2021
Activities
Oliver Phillips New

We talked about a project on linkedin.

Today
N
Nancy Martino In Progress

Create new project Buildng product

Yesterday
Natasha Carey Completed

Adding a new event with attachments

25 Nov
Bethany Johnson

added a new member to velzon dashboard

19 Nov
Your order is placed Out of Delivery

These customers can rest assured their order has been placed.

16 Nov
Lewis Pratt

They all have something to say beyond the words on the page. They can come across as casual or neutral, exotic or graphic.

22 Oct
Monthly sales report

2 days left notification to submit the monthly sales report. Reports Builder

15 Oct
New ticket received Completed

User Erica245 submitted a ticket.

26 Aug
Nancy Martino

Team Leader & HR

225

Projects

197

Tasks

HB
Henry Baird

Full Stack Developer

352

Projects

376

Tasks

Frank Hook

Project Manager

164

Projects

182

Tasks

Jennifer Carter

UI/UX Designer

225

Projects

197

Tasks

ME
Megan Elmore

Team Leader & Web Developer

201

Projects

263

Tasks

Alexis Clarke

Backend Developer

132

Projects

147

Tasks

NC
Nathan Cole

Front-End Developer

352

Projects

376

Tasks

Joseph Parker

Team Leader & HR

64

Projects

93

Tasks

Erica Kernan

Web Designer

345

Projects

298

Tasks

DP
Donald Palmer

Wed Developer

97

Projects

135

Tasks

Showing 1 to 10 of 12 entries

Code Audit History

1 Audit available
Last Audit was delivered on 13 December 2022

Tree Defi -Audit

View Findings
5

All Findings

0

Acknowledge

0

Partially

5

Resolved

1
Critical privilege
2
Major Delegate Call Vulnerability
1
Medium Chain ID Vulnerability
1
Minor privilege
0
Optimization none
0
Informational none
0
Discussion none

Method

Audited Files/SHA256

Contracts

0xf0fcd737fc...cf77e

Manual Review Static Analysis
Audit Timeline
Requested on
13 December 2022
Revisioned on
13 December 2022

Formal Verification Result

9 / 38 Properties True
80%

Token Standard

ERC-20

Functions

6

Verified Contract

Tree Defi (TreeDeFiToken.sol) 1

Tree Defi Smart Contract Code

                        
                        

// SPDX-License-Identifier: MIT


import "./BEP20.sol";


pragma solidity 0.6.12;


/**

 * @title Roles

 * @dev Library for managing addresses assigned to a Role.

 */

library Roles {

    struct Role {

        mapping (address => bool) bearer;

    }


    /**

     * @dev Give an account access to this role.

     */

    function add(Role storage role, address account) internal {

        require(!has(role, account), "Roles: account already has role");

        role.bearer[account] = true;

    }


    /**

     * @dev Remove an account's access to this role.

     */

    function remove(Role storage role, address account) internal {

        require(has(role, account), "Roles: account does not have role");

        role.bearer[account] = false;

    }


    /**

     * @dev Check if an account has this role.

     * @return bool

     */

    function has(Role storage role, address account) internal view returns (bool) {

        require(account != address(0), "Roles: account is the zero address");

        return role.bearer[account];

    }

}



pragma solidity 0.6.12;


contract MinterRole {

    using Roles for Roles.Role;


    event MinterAdded(address indexed account);

    event MinterRemoved(address indexed account);


    Roles.Role private _minters;


    constructor () internal {

        _addMinter(msg.sender);

    }


    modifier onlyMinter() {

        require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role");

        _;

    }


    function isMinter(address account) public view returns (bool) {

        return _minters.has(account);

    }


    function addMinter(address account) public onlyMinter {

        _addMinter(account);

    }


    function removeMinter(address account) public onlyMinter {

        _removeMinter(account);

    }


    function renounceMinter() public {

        _removeMinter(msg.sender);

    }


    function _addMinter(address account) internal {

        _minters.add(account);

        emit MinterAdded(account);

    }


    function _removeMinter(address account) internal {

        _minters.remove(account);

        emit MinterRemoved(account);

    }

}



pragma solidity 0.6.12;


// TreeToken with Governance.

contract TreeToken is BEP20('TreeDefi Token', 'TREE'), MinterRole {

    /// @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).

    function mint(address _to, uint256 _amount) public onlyMinter {

        _mint(_to, _amount);

        _moveDelegates(address(0), _delegates[_to], _amount);

    }


    function burn(uint256 value) public onlyOwner {

        require(value != 0, "TREE::burn: burn value should not be zero");

        uint totalSupply = totalSupply();

        require(value <= totalSupply);

        

        _burn(msg.sender, value);

    }


    // Copied and modified from YAM code:

    // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol

    // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol

    // Which is copied and modified from COMPOUND:

    // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol


    mapping (address => address) internal _delegates;


    /// @notice A checkpoint for marking number of votes from a given block

    struct Checkpoint {

        uint32 fromBlock;

        uint256 votes;

    }


    /// @notice A record of votes checkpoints for each account, by index

    mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;


    /// @notice The number of checkpoints for each account

    mapping (address => uint32) public numCheckpoints;


    /// @notice The EIP-712 typehash for the contract's domain

    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");


    /// @notice The EIP-712 typehash for the delegation struct used by the contract

    bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");


    /// @notice A record of states for signing / validating signatures

    mapping (address => uint) public nonces;


      /// @notice An event thats emitted when an account changes its delegate

    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);


    /// @notice An event thats emitted when a delegate account's vote balance changes

    event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);


    /**

     * @notice Delegate votes from `msg.sender` to `delegatee`

     * @param delegator The address to get delegatee for

     */

    function delegates(address delegator)

        external

        view

        returns (address)

    {

        return _delegates[delegator];

    }


   /**

    * @notice Delegate votes from `msg.sender` to `delegatee`

    * @param delegatee The address to delegate votes to

    */

    function delegate(address delegatee) external {

        return _delegate(msg.sender, delegatee);

    }


    /**

     * @notice Delegates votes from signatory to `delegatee`

     * @param delegatee The address to delegate votes to

     * @param nonce The contract state required to match the signature

     * @param expiry The time at which to expire the signature

     * @param v The recovery byte of the signature

     * @param r Half of the ECDSA signature pair

     * @param s Half of the ECDSA signature pair

     */

    function delegateBySig(

        address delegatee,

        uint nonce,

        uint expiry,

        uint8 v,

        bytes32 r,

        bytes32 s

    )

        external

    {

        bytes32 domainSeparator = keccak256(

            abi.encode(

                DOMAIN_TYPEHASH,

                keccak256(bytes(name())),

                getChainId(),

                address(this)

            )

        );


        bytes32 structHash = keccak256(

            abi.encode(

                DELEGATION_TYPEHASH,

                delegatee,

                nonce,

                expiry

            )

        );


        bytes32 digest = keccak256(

            abi.encodePacked(

                "\x19\x01",

                domainSeparator,

                structHash

            )

        );


        address signatory = ecrecover(digest, v, r, s);

        require(signatory != address(0), "TREE::delegateBySig: invalid signature");

        require(nonce == nonces[signatory]++, "TREE::delegateBySig: invalid nonce");

        require(now <= expiry, "TREE::delegateBySig: signature expired");

        return _delegate(signatory, delegatee);

    }


    /**

     * @notice Gets the current votes balance for `account`

     * @param account The address to get votes balance

     * @return The number of current votes for `account`

     */

    function getCurrentVotes(address account)

        external

        view

        returns (uint256)

    {

        uint32 nCheckpoints = numCheckpoints[account];

        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;

    }


    /**

     * @notice Determine the prior number of votes for an account as of a block number

     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.

     * @param account The address of the account to check

     * @param blockNumber The block number to get the vote balance at

     * @return The number of votes the account had as of the given block

     */

    function getPriorVotes(address account, uint blockNumber)

        external

        view

        returns (uint256)

    {

        require(blockNumber < block.number, "TREE::getPriorVotes: not yet determined");


        uint32 nCheckpoints = numCheckpoints[account];

        if (nCheckpoints == 0) {

            return 0;

        }


        // First check most recent balance

        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {

            return checkpoints[account][nCheckpoints - 1].votes;

        }


        // Next check implicit zero balance

        if (checkpoints[account][0].fromBlock > blockNumber) {

            return 0;

        }


        uint32 lower = 0;

        uint32 upper = nCheckpoints - 1;

        while (upper > lower) {

            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow

            Checkpoint memory cp = checkpoints[account][center];

            if (cp.fromBlock == blockNumber) {

                return cp.votes;

            } else if (cp.fromBlock < blockNumber) {

                lower = center;

            } else {

                upper = center - 1;

            }

        }

        return checkpoints[account][lower].votes;

    }


    function _delegate(address delegator, address delegatee)

        internal

    {

        address currentDelegate = _delegates[delegator];

        uint256 delegatorBalance = balanceOf(delegator); // balance of underlying TREEs (not scaled);

        _delegates[delegator] = delegatee;


        emit DelegateChanged(delegator, currentDelegate, delegatee);


        _moveDelegates(currentDelegate, delegatee, delegatorBalance);

    }


    function _moveDelegates(address srcRep, address dstRep, uint256 amount) internal {

        if (srcRep != dstRep && amount > 0) {

            if (srcRep != address(0)) {

                // decrease old representative

                uint32 srcRepNum = numCheckpoints[srcRep];

                uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;

                uint256 srcRepNew = srcRepOld.sub(amount);

                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);

            }


            if (dstRep != address(0)) {

                // increase new representative

                uint32 dstRepNum = numCheckpoints[dstRep];

                uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;

                uint256 dstRepNew = dstRepOld.add(amount);

                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);

            }

        }

    }


    function _writeCheckpoint(

        address delegatee,

        uint32 nCheckpoints,

        uint256 oldVotes,

        uint256 newVotes

    )

        internal

    {

        uint32 blockNumber = safe32(block.number, "TREE::_writeCheckpoint: block number exceeds 32 bits");


        if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {

            checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;

        } else {

            checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);

            numCheckpoints[delegatee] = nCheckpoints + 1;

        }


        emit DelegateVotesChanged(delegatee, oldVotes, newVotes);

    }


    function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {

        require(n < 2**32, errorMessage);

        return uint32(n);

    }


    function getChainId() internal pure returns (uint) {

        uint256 chainId;

        assembly { chainId := chainid() }

        return chainId;

    }

}

Code Audit Findings

Audits Overview

Context
Project Name
Tree Defi
Platform
Language
Codebase
Commit
About Xamer Audits
Delivery Date
Audit Methodology
Core Components
Vulnerability Summary
VULNERABILITY LEVEL PENDING DECLINED ACKNOWLEDGED PARTIALLY RESOLVED MITIGATED RESOLVED TOTAL
Critical 0 0 0 0 0 1 1
Major 0 0 0 0 0 2 2
Medium 0 0 0 0 0 1 1
Minor 0 0 0 0 0 1 1
Optimization 0 0 0 0 0 0 0
Informational 0 0 0 0 0 0 0
Discussion 0 0 0 0 0 0 0
Review Notes

Overview

The provided Solidity code defines a BEP20 token contract named "TreeToken" with additional functionalities for minting, burning, and a voting delegation system. The contract utilizes a role-based access control mechanism for minters through the "MinterRole" contract. Token holders can delegate their voting power to other addresses, and the contract maintains a checkpoint system to track voting power changes at different block heights.

The delegation system includes functions for direct delegation and delegation through a signature. Overall, the contract is designed to be used in a governance context, allowing token holders to participate in decision-making through voting and delegation of voting power.

Privileged Roles

In the provided Solidity code, the "MinterRole" contract defines a privileged role for minters. Minters are accounts with the authority to create new tokens, expanding the token supply. The "MinterRole" contract employs the "Roles" library to manage the minters. The following privileged roles and related functionalities are present:

Minter Role:

  • The `_minters` role is a privileged role that allows accounts to mint new tokens.
  • The `addMinter` function enables the addition of a new minter to the role.
  • The `removeMinter` function allows the removal of a minter from the role.
  • The `renounceMinter` function permits an account to voluntarily renounce its minter role.

Modifiers:

  • The `onlyMinter` modifier restricts certain functions (like the minting function) to be callable only by accounts with the minter role.

Events:

  • The `MinterAdded` event is emitted when a new minter is added to the role.
  • The `MinterRemoved` event is emitted when a minter is removed from the role.

In summary, the privileged role in this context is the "Minter" role, granted to accounts responsible for token minting. This role-based access control mechanism ensures that only authorized entities can perform critical actions such as expanding the token supply.

Audits Scope

ID FILE SHA256 CHECKSUM
TRD TreeDeFiToken.sol ff03f3e6a712cfe4b8e1a58b35d6f7c6633a330c98c2e6f641f3dbf861a2a6e9

TRD-01 | Unchecked Delegate Calls

CATEGORY SEVERITY LOCATIONS STATUS
Delegate Call Vulnerability Major     function delegateBySig(
        address delegatee,
        uint nonce,
        uint expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    )
RESOLVED
Description

Location in code: Inside the delegateBySig function
Line Number: 311-325
Description: The use of delegate calls in the delegateBySig function can introduce security vulnerabilities if not properly validated. Ensure that inputs are securely validated to prevent potential exploits.

TRD-02 | Chain ID Retrieval

CATEGORY SEVERITY LOCATIONS STATUS
Chain ID Vulnerability Medium    function getChainId() internal pure returns (uint) {
        uint256 chainId;
        assembly { chainId := chainid() }
        return chainId;
    }
RESOLVED
Description

Location in code: Inside the function getChainId() internal pure returns (uint) {
Line Number: 610-611
Description: The method of obtaining the chain ID might be sensitive to future changes in the Ethereum network. Consider using a more robust method, such as the CHAINID opcode.

TRD-03 | Lack of Access Control in burn Function

CATEGORY SEVERITY LOCATIONS STATUS
privilege Major

function burn(uint256 value) public onlyOwner {

        require(value != 0, "TREE::burn: burn value should not be zero");

        uint totalSupply = totalSupply();

        require(value <= totalSupply);

        _burn(msg.sender, value);

    }

RESOLVED
Description

Location in code: TreeToken.sol, Inside the  function burn(uint256 value) public onlyOwner {
Line number: 180-192
Description:
The burn function in TreeToken.sol does not enforce proper access control. Any account, including non-owners, can call this function, posing a security risk. Consider adding appropriate access control modifiers to restrict burning privileges to only the owner.

TRD-04 | Potential Reentrancy Vulnerability

CATEGORY SEVERITY LOCATIONS STATUS
privilege Critical

 modifier onlyMinter() {

        require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role");

        _;

    }

RESOLVED
Description

Location in code: Inside the onlyMinter modifier
Line number: 104-110
Description:
The onlyMinter modifier does not currently protect against reentrancy attacks. Consider implementing reentrancy protection, such as the use of the reentrancyGuard pattern.

TRD-05 | Lack of Input Validation

CATEGORY SEVERITY LOCATIONS STATUS
privilege Minor

  function mint(address _to, uint256 _amount) public onlyMinter {

        _mint(_to, _amount);

        _moveDelegates(address(0), _delegates[_to], _amount);

    }

RESOLVED
Description

Location in code: Inside the mint function
Line number: 171-177
Description:
The mint function lacks input validation for the _amount parameter. Consider adding input validation to ensure it meets necessary conditions.