World Ecosystem - Smart Contract Audit Report

Summary

World Audit Report The World team intends to build a unique platform that combines the best tokenomics of current frictionless yield protocols for instant rewards with the additional benefits of staking in our upcoming marketplace. This way the best rewards can be guaranteed without any token inflation.

World Token has been deployed to 0xBF494F02EE3FdE1F20BEE6242bCe2d1ED0c15e47.
World Farm has been deployed to 0x13701edcbd3a0bd958f7548e92c41272e2af7517.
World Swap has been deployed to 0x26fb0165ddbc47e3ce8dd349060b30385145d17e.
World OTC has been deployed to TBD.

WorldBSC has been deployed to TBD.

Notes on the Token Contract:
  • Transfers of the token contract incur a fee which is partially distributed among token holders.
  • There is a transaction fee (currently 3%) on transfers of the token. This fee is allocated for: redistribution of fees among holders, funding the team's marketing fund, funding the liquidity staking pool to fund rewards, and passing some fees to a merchant staking.
  • The owner is given the ability to include and exclude accounts from transfer fees.
  • The owner has the power to update the marketing, LP staking pool, and merchant staking address.
  • The owner also has the ability to update the tax fee percentages at any time to any amount. The team has implemented code to require that these tax amounts not exceed 10% total.
  • Utilization of SafeMath and SafeERC20 to prevent overflows and ensure safe transfers.
Notes on the Farm Contract:
  • Users can stake LP tokens from Uniswap to earn rewards in World tokens. Rewards are provided by the transaction fees associated with token transfers.
  • Reward rates vary based upon how many World tokens are in the contract and variables set by the owner.
  • Reward balances for users are updated every block.
  • The team can add new LP pools to provide rewards staking other LP tokens. The team cannot remove or update these pools.
  • The owner has the ability to update the rewards cycle, blocks per day, the World Token allocation point (used in rewards calculations), and the reward percentage (of the token balance of the contract) per block. The team has implemented limits on these variables to ensure that they cannot be abused.
  • Utilization of SafeMath to prevent overflows.
Notes on the WorldSwap Contract:
  • The WORLD token community has voiced some concerns over the gas fees incurred when buying and selling the token due to consistently high ETH network usage.
  • This contract allows users to buy and sell WORLD token, skipping the redistribution that occurs on each transfer, and saving a substantial amount of gas on each transaction.
  • This is achieved by routing Uniswap orders through this contract, which will be exempt from the fee incurred on transfers.
  • Utilization of SafeMath to prevent overflows.
Notes on the WorldOTC Contract:
  • This contract allows users to buy WORLD tokens directly from the project's treasury fund.
  • Tokens can be purchased with ETH at a predetermined rate and are vested to users over time in a separate & unique WorldVesting contract.
  • The default variables set the vesting period to 28 days with tokens being released every 7 days.
  • The team can set the rate that the token can be purchased at; as well as the vesting duration.
  • The team may also set the contract to a whitelist-only mode, where only pre-approved addresses may purchase from the contract.
  • Utilization of SafeMath to prevent overflows.

Notes on the WorldBSC Contract:
  • This contract will be deployed on the Binance Smart Chain (BSC) to allow users to hold the token on that chain.
  • The team utiliizes BurgerSwap's cross-chain bridge to wrap tokens on the ETH network and make them available on the BSC network.
  • This wrapping implementation allows the token to exist on multiple chains without disrupting the token's total supply.
  • Kindly note that our team has not audited Burgerswap's cross-chain bridge mechanism.

Audit Findings Summary:
  • No security issues from outside attackers were identified.
  • The team has worked with us to add controls in the contract to prevent setting of taxes or rewards to unreasonable rates.
  • The developer @worldtoken has completed KYC with our firm.
  • Date: January 20th, 2021.
  • Update Date: February 8th, 2020. Addition of analysis on WorldSwap contract.
  • Update Date: February 13th, 2020. Addition of analysis on WorldOTC contract.


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 AssertionN/APASS
Critical Solidity CompilerN/APASS
Overall Contract Safety PASS

Token Contract


Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Int] functionStaticCall
    - [Int] functionStaticCall
    - [Int] functionDelegateCall #
    - [Int] functionDelegateCall #
    - [Prv] _verifyCallResult

 + [Lib] SafeERC20 
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #
    - [Int] safeApprove #
    - [Int] safeIncreaseAllowance #
    - [Int] safeDecreaseAllowance #
    - [Prv] _callOptionalReturn #

 +  Ownable (Context)
    - [Int]  #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 +  WorldToken (Context, IERC20, Ownable)
    - [Pub]  #
    - [Ext] name
    - [Ext] symbol
    - [Ext] decimals
    - [Ext] totalSupply
    - [Pub] balanceOf
    - [Pub] transfer #
    - [Pub] allowance
    - [Pub] approve #
    - [Pub] transferFrom #
    - [Pub] increaseAllowance #
    - [Pub] decreaseAllowance #
    - [Ext] isExcludedFromReward
    - [Ext] isExcludedFromFee
    - [Ext] totalFees
    - [Pub] reflect #
    - [Pub] reflectionFromToken
    - [Pub] tokenFromReflection
    - [Pub] excludeFromFee #
       - modifiers: onlyOwner
    - [Pub] includeInFee #
       - modifiers: onlyOwner
    - [Pub] excludeFromReward #
       - modifiers: onlyOwner
    - [Pub] includeInReward #
       - modifiers: onlyOwner
    - [Prv] _approve #
    - [Prv] _transfer #
    - [Prv] _transferStandard #
    - [Prv] _transferToExcluded #
    - [Prv] _transferFromExcluded #
    - [Prv] _transferBothExcluded #
    - [Prv] _reflectFee #
    - [Prv] _reflectMarketingFee #
    - [Prv] _reflectLpFee #
    - [Prv] _reflectMerchantFee #
    - [Prv] _getValues
    - [Prv] _getTValues
    - [Prv] _getRValues
    - [Prv] _getRate
    - [Prv] _getCurrentSupply
    - [Prv] _getFee
    - [Prv] _getHolderFee
    - [Prv] _getMarketingFee
    - [Prv] _getLpFee
    - [Prv] _getMerchantFee
    - [Ext] setTaxPercentage #
       - modifiers: onlyOwner
    - [Ext] setTaxAllocations #
       - modifiers: onlyOwner
    - [Ext] setMarketingAddress #
       - modifiers: onlyOwner
    - [Ext] setLpStakingAddress #
       - modifiers: onlyOwner
    - [Ext] setMerchantStakingAddress #
       - modifiers: onlyOwner
	
							

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



/*
                                              ░░░░░░░░░░
                                        ░░░░░░████░░░░░░░░░░░░
                                    ░░░░░░░░██████░░░░░░░░░░░░░░░░
                                  ████░░░░░░░░████░░░░░░░░░░░░░░░░██
                                ████████░░░░██░░██░░░░░░░░░░░░░░██████
                                ██████████░░░░░░░░░░░░░░░░░░██████████
                              ████████████████████░░░░░░░░██████████████
                              ████████████░░██████░░░░░░░░██████████████
                              ██████████░░████████░░░░░░██████████░░░░██
                            ████████████████████░░░░░░░░████████░░░░░░░░██
                            ████████████████████░░░░░░░░░░████░░░░████████
                            ██████████████████░░░░░░░░░░░░░░░░████████████
                            ██████████████████░░░░░░░░░░░░░░██████████████
                            ░░░░░░░░░░██████░░░░░░░░░░░░░░░░██████████████
                              ░░░░░░░░░░░░██░░░░░░░░░░░░░░██████████████
                              ░░░░░░██░░░░██░░░░░░░░░░░░░░██████████████
                              ░░░░██░░░░░░░░░░░░░░░░░░░░░░██████████████
                                ░░░░░░░░░░░░░░░░░░░░░░░░░░████████████
                                ░░░░░░░░░░░░░░░░░░░░░░░░░░░░██████████
                                  ░░░░██░░░░░░░░░░░░░░░░░░░░████████
                                    ████░░░░░░░░░░░░░░░░░░░░██████
                                        ░░████░░░░░░░░░░░░░░░░
                                              ░░░░░░░░░░

    ██╗    ██╗ ██████╗ ██████╗ ██╗     ██████╗     ████████╗ ██████╗ ██╗  ██╗███████╗███╗   ██╗
    ██║    ██║██╔═══██╗██╔══██╗██║     ██╔══██╗    ╚══██╔══╝██╔═══██╗██║ ██╔╝██╔════╝████╗  ██║
    ██║ █╗ ██║██║   ██║██████╔╝██║     ██║  ██║       ██║   ██║   ██║█████╔╝ █████╗  ██╔██╗ ██║
    ██║███╗██║██║   ██║██╔══██╗██║     ██║  ██║       ██║   ██║   ██║██╔═██╗ ██╔══╝  ██║╚██╗██║
    ╚███╔███╔╝╚██████╔╝██║  ██║███████╗██████╔╝       ██║   ╚██████╔╝██║  ██╗███████╗██║ ╚████║
     ╚══╝╚══╝  ╚═════╝ ╚═╝  ╚═╝╚══════╝╚═════╝        ╚═╝    ╚═════╝ ╚═╝  ╚═╝╚══════╝╚═╝  ╚═══╝

*/

// SPDX-License-Identifier: MIT

pragma solidity 0.7.4;

import "@openzeppelin/audits/GSN/Context.sol";
import "@openzeppelin/audits/token/ERC20/IERC20.sol";
import "@openzeppelin/audits/math/SafeMath.sol";
import "@openzeppelin/audits/utils/Address.sol";
import "@openzeppelin/audits/access/Ownable.sol";

contract WorldToken is Context, IERC20, Ownable {
    using SafeMath for uint256;
    using Address for address;

    string private constant NAME = "World Token";
    string private constant SYMBOL = "WORLD";
    uint8 private constant DECIMALS = 18;

    mapping(address => uint256) private rewards;
    mapping(address => uint256) private actual;
    mapping(address => mapping(address => uint256)) private allowances;

    mapping(address => bool) private excludedFromFees;
    mapping(address => bool) private excludedFromRewards;
    address[] private rewardExcluded;

    uint256 private constant MAX = ~uint256(0);
    uint256 private constant ACTUAL_TOTAL = 100_000_000 * 1e18;
    uint256 private rewardsTotal = (MAX - (MAX % ACTUAL_TOTAL));
    uint256 private holderFeeTotal;
    uint256 private marketingFeeTotal;
    uint256 private lpFeeTotal;
    uint256 private merchantFeeTotal;

    uint256 public taxPercentage = 3;
    uint256 public holderTaxAlloc = 10;
    uint256 public marketingTaxAlloc = 10;
    uint256 public lpTaxAlloc = 10;
    uint256 public merchantTaxAlloc;
    uint256 public totalTaxAlloc = marketingTaxAlloc.add(holderTaxAlloc).add(lpTaxAlloc).add(merchantTaxAlloc);

    address public marketingAddress;
    address public lpStakingAddress;
    address public merchantStakingAddress;

    constructor(address _marketingAddress) {
        rewards[_marketingAddress] = rewardsTotal;
        emit Transfer(address(0), _marketingAddress, ACTUAL_TOTAL);

        marketingAddress = _marketingAddress;

        excludeFromRewards(_msgSender());
        excludeFromFees(_marketingAddress);

        if (_marketingAddress != _msgSender()) {
            excludeFromRewards(_marketingAddress);
            excludeFromFees(_msgSender());
        }

        excludeFromFees(address(0x000000000000000000000000000000000000dEaD));
    }

    function name() external pure returns (string memory) {
        return NAME;
    }

    function symbol() external pure returns (string memory) {
        return SYMBOL;
    }

    function decimals() external pure returns (uint8) {
        return DECIMALS;
    }

    function totalSupply() external pure override returns (uint256) {
        return ACTUAL_TOTAL;
    }

    function balanceOf(address _account) public view override returns (uint256) {
        if (excludedFromRewards[_account]) {
            return actual[_account];
        }
        return tokenWithRewards(rewards[_account]);
    }

    function transfer(address _recipient, uint256 _amount) public override returns (bool) {
        _transfer(_msgSender(), _recipient, _amount);
        return true;
    }

    function allowance(address _owner, address _spender) public view override returns (uint256) {
        return allowances[_owner][_spender];
    }

    function approve(address _spender, uint256 _amount) public override returns (bool) {
        _approve(_msgSender(), _spender, _amount);
        return true;
    }

    function transferFrom(
        address _sender,
        address _recipient,
        uint256 _amount
    ) public override returns (bool) {
        _transfer(_sender, _recipient, _amount);

        _approve(
        _sender,
            _msgSender(),
            allowances[_sender][_msgSender()].sub(_amount, "ERC20: transfer amount exceeds allowance")
        );

        return true;
    }

    function increaseAllowance(address _spender, uint256 _addedValue) public virtual returns (bool) {
        _approve(_msgSender(), _spender, allowances[_msgSender()][_spender].add(_addedValue));
        return true;
    }

    function decreaseAllowance(address _spender, uint256 _subtractedValue) public virtual returns (bool) {
        _approve(
            _msgSender(),
            _spender,
            allowances[_msgSender()][_spender].sub(_subtractedValue, "ERC20: decreased allowance below zero")
        );
        return true;
    }

    function isExcludedFromRewards(address _account) external view returns (bool) {
        return excludedFromRewards[_account];
    }

    function isExcludedFromFees(address _account) external view returns (bool) {
        return excludedFromFees[_account];
    }

    function totalFees() external view returns (uint256) {
        return holderFeeTotal.add(marketingFeeTotal).add(lpFeeTotal).add(merchantFeeTotal);
    }

    function totalHolderFees() external view returns (uint256) {
        return holderFeeTotal;
    }

    function totalMarketingFees() external view returns (uint256) {
        return marketingFeeTotal;
    }

    function totalLpFees() external view returns (uint256) {
        return lpFeeTotal;
    }

    function totalMerchantFees() external view returns (uint256) {
        return merchantFeeTotal;
    }

    function distribute(uint256 _actualAmount) public {
        address sender = _msgSender();
        require(!excludedFromRewards[sender], "Excluded addresses cannot call this function");

        (uint256 rewardAmount, , , , ) = _getValues(_actualAmount);
        rewards[sender] = rewards[sender].sub(rewardAmount);
        rewardsTotal = rewardsTotal.sub(rewardAmount);
        holderFeeTotal = holderFeeTotal.add(_actualAmount);
    }

    function excludeFromFees(address _account) public onlyOwner() {
        require(!excludedFromFees[_account], "Account is already excluded from fee");
        excludedFromFees[_account] = true;
    }

    function includeInFees(address _account) public onlyOwner() {
        require(excludedFromFees[_account], "Account is already included in fee");
        excludedFromFees[_account] = false;
    }

    function excludeFromRewards(address _account) public onlyOwner() {
        require(!excludedFromRewards[_account], "Account is already excluded from reward");

        if (rewards[_account] > 0) {
            actual[_account] = tokenWithRewards(rewards[_account]);
        }

        excludedFromRewards[_account] = true;
        rewardExcluded.push(_account);
    }

    function includeInRewards(address _account) public onlyOwner() {
        require(excludedFromRewards[_account], "Account is already included in rewards");

        for (uint256 i = 0; i < rewardExcluded.length; i++) {
            if (rewardExcluded[i] == _account) {
                rewardExcluded[i] = rewardExcluded[rewardExcluded.length - 1];
                actual[_account] = 0;
                excludedFromRewards[_account] = false;
                rewardExcluded.pop();
                break;
            }
        }
    }

    function _approve(
        address _owner,
        address _spender,
        uint256 _amount
    ) private {
        require(_owner != address(0), "ERC20: approve from the zero address");
        require(_spender != address(0), "ERC20: approve to the zero address");

        allowances[_owner][_spender] = _amount;
        emit Approval(_owner, _spender, _amount);
    }

    function _transfer(
        address _sender,
        address _recipient,
        uint256 _amount
    ) private {
        require(_sender != address(0), "ERC20: transfer from the zero address");
        require(_recipient != address(0), "ERC20: transfer to the zero address");
        require(_amount > 0, "Transfer amount must be greater than zero");

        uint256 currentTaxPercentage = taxPercentage;
        if (excludedFromFees[_sender] || excludedFromFees[_recipient]) {
            taxPercentage = 0;
        } else {
            uint256 fee = _getFee(_amount);
            uint256 marketingFee = _getMarketingFee(fee);
            uint256 lpFee = _getLpFee(fee);
            uint256 merchantFee = _getMerchantFee(fee);

            _updateMarketingFee(marketingFee);
            _updateLpFee(lpFee);
            _updateMerchantFee(merchantFee);
        }

        if (excludedFromRewards[_sender] && !excludedFromRewards[_recipient]) {
            _transferWithoutSenderRewards(_sender, _recipient, _amount);
        } else if (!excludedFromRewards[_sender] && excludedFromRewards[_recipient]) {
            _transferWithRecipientRewards(_sender, _recipient, _amount);
        } else if (!excludedFromRewards[_sender] && !excludedFromRewards[_recipient]) {
            _transferWithRewards(_sender, _recipient, _amount);
        } else if (excludedFromRewards[_sender] && excludedFromRewards[_recipient]) {
            _transferWithoutRewards(_sender, _recipient, _amount);
        } else {
            _transferWithRewards(_sender, _recipient, _amount);
        }

        if (currentTaxPercentage != taxPercentage) {
            taxPercentage = currentTaxPercentage;
        }
    }

    function _transferWithRewards(
        address _sender,
        address _recipient,
        uint256 _actualAmount
    ) private {
        (
            uint256 rewardAmount,
            uint256 rewardTransferAmount,
            uint256 rewardFee,
            uint256 actualTransferAmount,
            uint256 actualFee
        ) = _getValues(_actualAmount);

        rewards[_sender] = rewards[_sender].sub(rewardAmount);
        rewards[_recipient] = rewards[_recipient].add(rewardTransferAmount);
        _updateHolderFee(rewardFee, actualFee);
        emit Transfer(_sender, _recipient, actualTransferAmount);
    }

    function _transferWithRecipientRewards(
        address _sender,
        address _recipient,
        uint256 _actualAmount
    ) private {
        (
            uint256 rewardAmount,
            uint256 rewardTransferAmount,
            uint256 rewardFee,
            uint256 actualTransferAmount,
            uint256 actualFee
        ) = _getValues(_actualAmount);

        rewards[_sender] = rewards[_sender].sub(rewardAmount);
        actual[_recipient] = actual[_recipient].add(actualTransferAmount);
        rewards[_recipient] = rewards[_recipient].add(rewardTransferAmount);
        _updateHolderFee(rewardFee, actualFee);
        emit Transfer(_sender, _recipient, actualTransferAmount);
    }

    function _transferWithoutSenderRewards(
        address _sender,
        address _recipient,
        uint256 _actualAmount
    ) private {
        (
            uint256 rewardAmount,
            uint256 rewardTransferAmount,
            uint256 rewardFee,
            uint256 actualTransferAmount,
            uint256 actualFee
        ) = _getValues(_actualAmount);

        actual[_sender] = actual[_sender].sub(_actualAmount);
        rewards[_sender] = rewards[_sender].sub(rewardAmount);
        rewards[_recipient] = rewards[_recipient].add(rewardTransferAmount);
        _updateHolderFee(rewardFee, actualFee);
        emit Transfer(_sender, _recipient, actualTransferAmount);
    }

    function _transferWithoutRewards(
        address _sender,
        address _recipient,
        uint256 _actualAmount
    ) private {
        (
            uint256 rewardAmount,
            uint256 rewardTransferAmount,
            uint256 rewardFee,
            uint256 actualTransferAmount,
            uint256 actualFee
        ) = _getValues(_actualAmount);

        actual[_sender] = actual[_sender].sub(_actualAmount);
        rewards[_sender] = rewards[_sender].sub(rewardAmount);
        actual[_recipient] = actual[_recipient].add(actualTransferAmount);
        rewards[_recipient] = rewards[_recipient].add(rewardTransferAmount);
        _updateHolderFee(rewardFee, actualFee);
        emit Transfer(_sender, _recipient, actualTransferAmount);
    }

    function _updateHolderFee(uint256 _rewardFee, uint256 _actualFee) private {
        rewardsTotal = rewardsTotal.sub(_rewardFee);
        holderFeeTotal = holderFeeTotal.add(_actualFee);
    }

    function _updateMarketingFee(uint256 _marketingFee) private {
        if (marketingAddress == address(0)) {
            return;
        }

        uint256 rewardsRate = _getRewardsRate();
        uint256 rewardMarketingFee = _marketingFee.mul(rewardsRate);
        marketingFeeTotal = marketingFeeTotal.add(_marketingFee);

        rewards[marketingAddress] = rewards[marketingAddress].add(rewardMarketingFee);
        if (excludedFromRewards[marketingAddress]) {
            actual[marketingAddress] = actual[marketingAddress].add(_marketingFee);
        }
    }

    function _updateLpFee(uint256 _lpFee) private {
        if (lpStakingAddress == address(0)) {
            return;
        }

        uint256 rewardsRate = _getRewardsRate();
        uint256 rewardLpFee = _lpFee.mul(rewardsRate);
        lpFeeTotal = lpFeeTotal.add(_lpFee);

        rewards[lpStakingAddress] = rewards[lpStakingAddress].add(rewardLpFee);
        if (excludedFromRewards[lpStakingAddress]) {
            actual[lpStakingAddress] = actual[lpStakingAddress].add(_lpFee);
        }
    }

    function _updateMerchantFee(uint256 _merchantFee) private {
        if (merchantStakingAddress == address(0)) {
            return;
        }

        uint256 rewardsRate = _getRewardsRate();
        uint256 rewardMerchantFee = _merchantFee.mul(rewardsRate);
        merchantFeeTotal = merchantFeeTotal.add(_merchantFee);

        rewards[merchantStakingAddress] = rewards[merchantStakingAddress].add(rewardMerchantFee);
        if (excludedFromRewards[merchantStakingAddress]) {
            actual[merchantStakingAddress] = actual[merchantStakingAddress].add(_merchantFee);
        }
    }

    function rewardsFromToken(uint256 _actualAmount, bool _deductTransferFee) public view returns (uint256) {
        require(_actualAmount <= ACTUAL_TOTAL, "Amount must be less than supply");
        if (!_deductTransferFee) {
            (uint256 rewardAmount, , , , ) = _getValues(_actualAmount);
            return rewardAmount;
        } else {
            (, uint256 rewardTransferAmount, , , ) = _getValues(_actualAmount);
            return rewardTransferAmount;
        }
    }

    function tokenWithRewards(uint256 _rewardAmount) public view returns (uint256) {
        require(_rewardAmount <= rewardsTotal, "Amount must be less than total rewards");
        uint256 rewardsRate = _getRewardsRate();
        return _rewardAmount.div(rewardsRate);
    }

    function _getValues(uint256 _actualAmount)
        private
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256,
            uint256
        )
    {
        (uint256 actualTransferAmount, uint256 actualFee) = _getActualValues(_actualAmount);
        uint256 rewardsRate = _getRewardsRate();
        (
            uint256 rewardAmount,
            uint256 rewardTransferAmount,
            uint256 rewardFee
        ) = _getRewardValues(_actualAmount, actualFee, rewardsRate);

        return (rewardAmount, rewardTransferAmount, rewardFee, actualTransferAmount, actualFee);
    }

    function _getActualValues(uint256 _actualAmount) private view returns (uint256, uint256) {
        uint256 actualFee = _getFee(_actualAmount);
        uint256 actualHolderFee = _getHolderFee(actualFee);
        uint256 actualTransferAmount = _actualAmount.sub(actualFee);
        return (actualTransferAmount, actualHolderFee);
    }

    function _getRewardValues(
        uint256 _actualAmount,
        uint256 _actualHolderFee,
        uint256 _rewardsRate
    )
        private
        view
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        uint256 actualFee = _getFee(_actualAmount).mul(_rewardsRate);
        uint256 rewardAmount = _actualAmount.mul(_rewardsRate);
        uint256 rewardTransferAmount = rewardAmount.sub(actualFee);
        uint256 rewardFee = _actualHolderFee.mul(_rewardsRate);
        return (rewardAmount, rewardTransferAmount, rewardFee);
    }

    function _getRewardsRate() private view returns (uint256) {
        (uint256 rewardsSupply, uint256 actualSupply) = _getCurrentSupply();
        return rewardsSupply.div(actualSupply);
    }

    function _getCurrentSupply() private view returns (uint256, uint256) {
        uint256 rewardsSupply = rewardsTotal;
        uint256 actualSupply = ACTUAL_TOTAL;

        for (uint256 i = 0; i < rewardExcluded.length; i++) {
            if (rewards[rewardExcluded[i]] > rewardsSupply || actual[rewardExcluded[i]] > actualSupply) {
                return (rewardsTotal, ACTUAL_TOTAL);
            }

            rewardsSupply = rewardsSupply.sub(rewards[rewardExcluded[i]]);
            actualSupply = actualSupply.sub(actual[rewardExcluded[i]]);
        }

        if (rewardsSupply < rewardsTotal.div(ACTUAL_TOTAL)) {
            return (rewardsTotal, ACTUAL_TOTAL);
        }

        return (rewardsSupply, actualSupply);
    }

    function _getFee(uint256 _amount) private view returns (uint256) {
        return _amount.mul(taxPercentage).div(100);
    }

    function _getHolderFee(uint256 _tax) private view returns (uint256) {
        return _tax.mul(holderTaxAlloc).div(totalTaxAlloc);
    }

    function _getMarketingFee(uint256 _tax) private view returns (uint256) {
        return _tax.mul(marketingTaxAlloc).div(totalTaxAlloc);
    }

    function _getLpFee(uint256 _tax) private view returns (uint256) {
        return _tax.mul(lpTaxAlloc).div(totalTaxAlloc);
    }

    function _getMerchantFee(uint256 _tax) private view returns (uint256) {
        return _tax.mul(merchantTaxAlloc).div(totalTaxAlloc);
    }

    function setTaxPercentage(uint256 _taxPercentage) external onlyOwner {
        require(_taxPercentage >= 1 && _taxPercentage <= 10, "Value is outside of range 1-10");
        taxPercentage = _taxPercentage;
    }

    function setTaxAllocations(
        uint256 _holderTaxAlloc,
        uint256 _marketingTaxAlloc,
        uint256 _lpTaxAlloc,
        uint256 _merchantTaxAlloc
    ) external onlyOwner {
        totalTaxAlloc = _holderTaxAlloc.add(_marketingTaxAlloc).add(_lpTaxAlloc).add(_merchantTaxAlloc);

        require(_holderTaxAlloc >= 5 && _holderTaxAlloc <= 10, "_holderTaxAlloc is outside of range 5-10");
        require(_lpTaxAlloc >= 5 && _lpTaxAlloc <= 10, "_lpTaxAlloc is outside of range 5-10");
        require(_marketingTaxAlloc <= 10, "_marketingTaxAlloc is greater than 10");
        require(_merchantTaxAlloc <= 10, "_merchantTaxAlloc is greater than 10");

        holderTaxAlloc = _holderTaxAlloc;
        marketingTaxAlloc = _marketingTaxAlloc;
        lpTaxAlloc = _lpTaxAlloc;
        merchantTaxAlloc = _merchantTaxAlloc;
    }

    function setMarketingAddress(address _marketingAddress) external onlyOwner {
        marketingAddress = _marketingAddress;
    }

    function setLpStakingAddress(address _lpStakingAddress) external onlyOwner {
        lpStakingAddress = _lpStakingAddress;
    }

    function setMerchantStakingAddress(address _merchantStakingAddress) external onlyOwner {
        merchantStakingAddress = _merchantStakingAddress;
    }
}

Farm Contract


Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Int] functionStaticCall
    - [Int] functionStaticCall
    - [Int] functionDelegateCall #
    - [Int] functionDelegateCall #
    - [Prv] _verifyCallResult

 + [Lib] SafeERC20 
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #
    - [Int] safeApprove #
    - [Int] safeIncreaseAllowance #
    - [Int] safeDecreaseAllowance #
    - [Prv] _callOptionalReturn #

 +  Ownable (Context)
    - [Int]  #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 +  WorldToken (Context, IERC20, Ownable)
    - [Pub]  #
    - [Ext] name
    - [Ext] symbol
    - [Ext] decimals
    - [Ext] totalSupply
    - [Pub] balanceOf
    - [Pub] transfer #
    - [Pub] allowance
    - [Pub] approve #
    - [Pub] transferFrom #
    - [Pub] increaseAllowance #
    - [Pub] decreaseAllowance #
    - [Ext] isExcludedFromReward
    - [Ext] isExcludedFromFee
    - [Ext] totalFees
    - [Pub] reflect #
    - [Pub] reflectionFromToken
    - [Pub] tokenFromReflection
    - [Pub] excludeFromFee #
       - modifiers: onlyOwner
    - [Pub] includeInFee #
       - modifiers: onlyOwner
    - [Pub] excludeFromReward #
       - modifiers: onlyOwner
    - [Pub] includeInReward #
       - modifiers: onlyOwner
    - [Prv] _approve #
    - [Prv] _transfer #
    - [Prv] _transferStandard #
    - [Prv] _transferToExcluded #
    - [Prv] _transferFromExcluded #
    - [Prv] _transferBothExcluded #
    - [Prv] _reflectFee #
    - [Prv] _reflectMarketingFee #
    - [Prv] _reflectLpFee #
    - [Prv] _reflectMerchantFee #
    - [Prv] _getValues
    - [Prv] _getTValues
    - [Prv] _getRValues
    - [Prv] _getRate
    - [Prv] _getCurrentSupply
    - [Prv] _getFee
    - [Prv] _getHolderFee
    - [Prv] _getMarketingFee
    - [Prv] _getLpFee
    - [Prv] _getMerchantFee
    - [Ext] setTaxPercentage #
       - modifiers: onlyOwner
    - [Ext] setTaxAllocations #
       - modifiers: onlyOwner
    - [Ext] setMarketingAddress #
       - modifiers: onlyOwner
    - [Ext] setLpStakingAddress #
       - modifiers: onlyOwner
    - [Ext] setMerchantStakingAddress #
       - modifiers: onlyOwner

							

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


// SPDX-License-Identifier: MIT

pragma solidity 0.7.4;

import "@openzeppelin/audits/token/ERC20/IERC20.sol";
import "@openzeppelin/audits/token/ERC20/SafeERC20.sol";
import "@openzeppelin/audits/math/SafeMath.sol";
import "@openzeppelin/audits/access/Ownable.sol";
import "./WorldToken.sol";

contract WorldFarm is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    // Info of each user.
    struct UserInfo {
        uint256 amount; // How many LP tokens the user has provided.
        uint256 rewardDebt; // Reward debt. See explanation below.
        //
        // We do some fancy math here. Basically, any point in time, the amount of WORLD tokens
        // entitled to a user but is pending to be distributed is:
        //
        //   pending reward = (user.amount * pool.accWorldPerShare) - user.rewardDebt
        //
        // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:
        //   1. The pool's `accWorldPerShare` (and `lastRewardBlock`) gets updated.
        //   2. User receives the pending reward sent to his/her address.
        //   3. User's `amount` gets updated.
        //   4. User's `rewardDebt` gets updated.
    }

    // Info of each pool.
    struct PoolInfo {
        IERC20 lpToken; // Address of LP token contract.
        uint256 allocPoint; // How many allocation points assigned to this pool. WORLD tokens to distribute per block.
        uint256 lastRewardBlock; // Last block number that WORLD tokens distribution occurs.
        uint256 accWorldPerShare; // Accumulated WORLD tokens per share, times 1e12. See below.
    }

    WorldToken public immutable world; // The WORLD ERC-20 Token.
    uint256 private worldPerBlock; // WORLD tokens distributed per block. Use getWorldPerBlock() to get the updated reward.

    PoolInfo[] public poolInfo; // Info of each pool.
    mapping(uint256 => mapping(address => UserInfo)) public userInfo; // Info of each user that stakes LP tokens.
    uint256 public totalAllocPoint; // Total allocation points. Must be the sum of all allocation points in all pools.
    uint256 public startBlock; // The block number when WORLD token mining starts.

    uint256 public blockRewardUpdateCycle = 1 days; // The cycle in which the worldPerBlock gets updated.
    uint256 public blockRewardLastUpdateTime = block.timestamp; // The timestamp when the block worldPerBlock was last updated.
    uint256 public blocksPerDay = 6525; // The estimated number of mined blocks per day.
    uint256 public blockRewardPercentage = 1; // The percentage used for worldPerBlock calculation.

    mapping(address => bool) public addedLpTokens; // Used for preventing LP tokens from being added twice in add().

    event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
    event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);

    constructor(
        WorldToken _world,
        uint256 _startBlock
    ) {
        require(address(_world) != address(0), "WORLD address is invalid");
        require(_startBlock >= block.number, "startBlock is before current block");

        world = _world;
        startBlock = _startBlock;
    }

    modifier updateWorldPerBlock() {
        (uint256 blockReward, bool update) = getWorldPerBlock();
        if (update) {
            worldPerBlock = blockReward;
            blockRewardLastUpdateTime = block.timestamp;
        }
        _;
    }

    function getWorldPerBlock() public view returns (uint256, bool) {
        if (block.number < startBlock) {
            return (0, false);
        }

        uint256 poolReward = world.balanceOf(address(this));
        if (poolReward == 0) {
            return (0, worldPerBlock != 0);
        }

        if (block.timestamp >= getWorldPerBlockUpdateTime() || worldPerBlock == 0) {
            return (poolReward.mul(blockRewardPercentage).div(100).div(blocksPerDay), true);
        }

        return (worldPerBlock, false);
    }

    function getWorldPerBlockUpdateTime() public view returns (uint256) {
        // if blockRewardUpdateCycle = 1 day then roundedUpdateTime = today's UTC midnight
        uint256 roundedUpdateTime = blockRewardLastUpdateTime - (blockRewardLastUpdateTime % blockRewardUpdateCycle);
        // if blockRewardUpdateCycle = 1 day then calculateRewardTime = tomorrow's UTC midnight
        uint256 calculateRewardTime = roundedUpdateTime + blockRewardUpdateCycle;
        return calculateRewardTime;
    }

    function poolLength() external view returns (uint256) {
        return poolInfo.length;
    }

    // Add a new lp to the pool. Can only be called by the owner.
    function add(
        uint256 _allocPoint,
        IERC20 _lpToken,
        bool _withUpdate
    ) public onlyOwner {
        require(address(_lpToken) != address(0), "LP token is invalid");
        require(!addedLpTokens[address(_lpToken)], "LP token is already added");

        require(_allocPoint >= 5 && _allocPoint <= 10, "_allocPoint is outside of range 5-10");

        if (_withUpdate) {
            massUpdatePools();
        }
        uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
        totalAllocPoint = totalAllocPoint.add(_allocPoint);
        poolInfo.push(PoolInfo({
            lpToken : _lpToken,
            allocPoint : _allocPoint,
            lastRewardBlock : lastRewardBlock,
            accWorldPerShare : 0
        }));

        addedLpTokens[address(_lpToken)] = true;
    }

    // Update the given pool's WORLD token allocation point. Can only be called by the owner.
    function set(
        uint256 _pid,
        uint256 _allocPoint,
        bool _withUpdate
    ) public onlyOwner {
        require(_allocPoint >= 5 && _allocPoint <= 10, "_allocPoint is outside of range 5-10");

        if (_withUpdate) {
            massUpdatePools();
        }
        totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint);
        poolInfo[_pid].allocPoint = _allocPoint;
    }

    // View function to see pending WORLD tokens on frontend.
    function pendingRewards(uint256 _pid, address _user) external view returns (uint256) {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        uint256 accWorldPerShare = pool.accWorldPerShare;
        uint256 lpSupply = pool.lpToken.balanceOf(address(this));
        if (block.number > pool.lastRewardBlock && lpSupply != 0) {
            uint256 multiplier = block.number.sub(pool.lastRewardBlock);
            (uint256 blockReward, ) = getWorldPerBlock();
            uint256 worldReward = multiplier.mul(blockReward).mul(pool.allocPoint).div(totalAllocPoint);
            accWorldPerShare = accWorldPerShare.add(worldReward.mul(1e12).div(lpSupply));
        }
        return user.amount.mul(accWorldPerShare).div(1e12).sub(user.rewardDebt);
    }

    // Update reward variables for all pools. Be careful of gas spending!
    function massUpdatePools() public {
        uint256 length = poolInfo.length;
        for (uint256 pid = 0; pid < length; ++pid) {
            updatePool(pid);
        }
    }

    // Update reward variables of the given pool to be up-to-date when lpSupply changes
    // For every deposit/withdraw pool recalculates accumulated token value
    function updatePool(uint256 _pid) public updateWorldPerBlock {
        PoolInfo storage pool = poolInfo[_pid];
        if (block.number <= pool.lastRewardBlock) {
            return;
        }

        uint256 lpSupply = pool.lpToken.balanceOf(address(this));
        if (lpSupply == 0) {
            pool.lastRewardBlock = block.number;
            return;
        }

        uint256 multiplier = block.number.sub(pool.lastRewardBlock);
        uint256 worldReward = multiplier.mul(worldPerBlock).mul(pool.allocPoint).div(totalAllocPoint);

        // no minting is required, the contract should have WORLD token balance pre-allocated
        // accumulated WORLD per share is stored multiplied by 10^12 to allow small 'fractional' values
        pool.accWorldPerShare = pool.accWorldPerShare.add(worldReward.mul(1e12).div(lpSupply));
        pool.lastRewardBlock = block.number;
    }

    // Deposit LP tokens to WorldFarming for WORLD token allocation.
    function deposit(uint256 _pid, uint256 _amount) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];

        updatePool(_pid);

        if (user.amount > 0) {
            uint256 pending = user.amount.mul(pool.accWorldPerShare).div(1e12).sub(user.rewardDebt);
            if (pending > 0) {
                safeTokenTransfer(msg.sender, pending);
            }
        }
        if (_amount > 0) {
            pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
            user.amount = user.amount.add(_amount);
        }
        user.rewardDebt = user.amount.mul(pool.accWorldPerShare).div(1e12);
        emit Deposit(msg.sender, _pid, _amount);
    }

    // Withdraw LP tokens from WorldFarming
    function withdraw(uint256 _pid, uint256 _amount) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount >= _amount, "Withdraw amount is greater than user amount");

        updatePool(_pid);

        uint256 pending = user.amount.mul(pool.accWorldPerShare).div(1e12).sub(user.rewardDebt);
        if (pending > 0) {
            safeTokenTransfer(msg.sender, pending);
        }
        if (_amount > 0) {
            user.amount = user.amount.sub(_amount);
            pool.lpToken.safeTransfer(address(msg.sender), _amount);
        }
        user.rewardDebt = user.amount.mul(pool.accWorldPerShare).div(1e12);
        emit Withdraw(msg.sender, _pid, _amount);
    }

    // Withdraw without caring about rewards. EMERGENCY ONLY.
    function emergencyWithdraw(uint256 _pid) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];

        user.amount = 0;
        user.rewardDebt = 0;

        pool.lpToken.safeTransfer(address(msg.sender), user.amount);
        emit EmergencyWithdraw(msg.sender, _pid, user.amount);
    }

    // Safe WORLD token transfer function, just in case if
    // rounding error causes pool to not have enough WORLD tokens
    function safeTokenTransfer(address _to, uint256 _amount) internal {
        uint256 balance = world.balanceOf(address(this));
        uint256 amount = _amount > balance ? balance : _amount;
        world.transfer(_to, amount);
    }

    function setBlockRewardUpdateCycle(uint256 _blockRewardUpdateCycle) external onlyOwner {
        require(_blockRewardUpdateCycle > 0, "Value is zero");
        blockRewardUpdateCycle = _blockRewardUpdateCycle;
    }

    // Just in case an adjustment is needed since mined blocks per day
    // changes constantly depending on the network
    function setBlocksPerDay(uint256 _blocksPerDay) external onlyOwner {
        require(_blocksPerDay >= 6200 && _blocksPerDay <= 7000, "Value is outside of range 6200-7000");
        blocksPerDay = _blocksPerDay;
    }

    function setBlockRewardPercentage(uint256 _blockRewardPercentage) external onlyOwner {
        require(_blockRewardPercentage >= 1 && _blockRewardPercentage <= 5, "Value is outside of range 1-5");
        blockRewardPercentage = _blockRewardPercentage;
    }
}

WorldSwap Contract


Smart Contract Graph

Contract Inheritance


 ($) = 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] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

 + [Int] IWorldToken (IERC20)
    - [Ext] distribute #

 + [Int] IUniswapV2Router02 
    - [Ext] swapExactETHForTokens ($)
    - [Ext] swapExactTokensForETH #

 +  WorldSwap 
    - [Pub]  #
    - [Ext] buy ($)
    - [Ext] buyWithPath ($)
    - [Ext] sell #
    - [Ext] sellWithPath #
    - [Ext] distributeRewards #

							

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


// SPDX-License-Identifier: MIT

pragma solidity 0.7.4;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

interface IWorldToken is IERC20 {
    function distribute(uint256 _actualAmount) external;
}

interface IUniswapV2Router02 {
    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint[] memory amounts);
}

contract WorldSwap {
    using SafeMath for uint256;

    constructor() {
        // WORLD
        IERC20(address(0xBF494F02EE3FdE1F20BEE6242bCe2d1ED0c15e47)).approve(
            address(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D), // Uniswap
            ~uint256(0)
        );
    }

    function buy(uint256 amountOutMin, uint256 deadline) external payable {
        address[] memory path = new address[](2);
        path[0] = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // WETH
        path[1] = address(0xBF494F02EE3FdE1F20BEE6242bCe2d1ED0c15e47); // WORLD

        uint256[] memory amount = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D).swapExactETHForTokens{value: msg.value}(
            amountOutMin,
            path,
            address(this),
            deadline
        );

        IERC20(path[1]).transfer(
            msg.sender,
            amount[1].sub(amount[1].mul(3).div(100))
        );
    }

    function buyWithPath(uint256 amountOutMin, address[] calldata path, uint256 deadline) external payable {
        address world = path[path.length - 1];
        require(world == address(0xBF494F02EE3FdE1F20BEE6242bCe2d1ED0c15e47), "Last path element is not WORLD");

        uint256[] memory amount = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D).swapExactETHForTokens{value: msg.value}(
            amountOutMin,
            path,
            address(this),
            deadline
        );

        uint256 worldAmount = amount[path.length - 1];
        IERC20(world).transfer(
            msg.sender,
            worldAmount.sub(worldAmount.mul(3).div(100))
        );
    }

    function sell(uint256 amountIn, uint256 amountOutMin, uint256 deadline) external {
        address[] memory path = new address[](2);
        path[0] = address(0xBF494F02EE3FdE1F20BEE6242bCe2d1ED0c15e47); // WORLD
        path[1] = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); // WETH

        IERC20(path[0]).transferFrom(
            msg.sender,
            address(this),
            amountIn
        );

        IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D).swapExactTokensForETH(
            amountIn.sub(amountIn.mul(3).div(100)),
            amountOutMin,
            path,
            msg.sender,
            deadline
        );
    }

    function sellWithPath(uint256 amountIn, uint256 amountOutMin, address[] calldata path, uint256 deadline) external {
        require(path[0] == address(0xBF494F02EE3FdE1F20BEE6242bCe2d1ED0c15e47), "First path element is not WORLD");

        IERC20(path[0]).transferFrom(
            msg.sender,
            address(this),
            amountIn
        );

        IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D).swapExactTokensForETH(
            amountIn.sub(amountIn.mul(3).div(100)),
            amountOutMin,
            path,
            msg.sender,
            deadline
        );
    }

    function distributeRewards() external {
        IWorldToken world = IWorldToken(address(0xBF494F02EE3FdE1F20BEE6242bCe2d1ED0c15e47));
        uint256 balance = world.balanceOf(address(this));
        uint256 rewards = balance.div(3);

        if (balance == 0 || rewards == 0) {
            return;
        }

        world.distribute(rewards);
        world.transfer(address(0xD4713A489194eeE0ccaD316a0A6Ec2322290B4F9), rewards); // marketingAddress
        world.transfer(address(0x13701EdCBD3A0BD958F7548E92c41272E2AF7517), rewards); // lpStakingAddress
    }
}


WorldOTC Contract


Smart Contract Graph

Contract Inheritance


 ($) = payable function
 # = non-constant function
 
 Int = Internal
 Ext = External
 Pub = Public
 
 +  Context 
    - [Int] _msgSender
    - [Int] _msgData

 +  Ownable (Context)
    - [Pub]  #
    - [Pub] owner
    - [Pub] renounceOwnership #
       - modifiers: onlyOwner
    - [Pub] transferOwnership #
       - modifiers: onlyOwner

 + [Lib] Clones 
    - [Int] clone #
    - [Int] cloneDeterministic #
    - [Int] predictDeterministicAddress
    - [Int] predictDeterministicAddress

 + [Int] IERC20 
    - [Ext] totalSupply
    - [Ext] balanceOf
    - [Ext] transfer #
    - [Ext] allowance
    - [Ext] approve #
    - [Ext] transferFrom #

 + [Lib] Address 
    - [Int] isContract
    - [Int] sendValue #
    - [Int] functionCall #
    - [Int] functionCall #
    - [Int] functionCallWithValue #
    - [Int] functionCallWithValue #
    - [Int] functionStaticCall
    - [Int] functionStaticCall
    - [Int] functionDelegateCall #
    - [Int] functionDelegateCall #
    - [Prv] _verifyCallResult

 + [Lib] SafeMath 
    - [Int] tryAdd
    - [Int] trySub
    - [Int] tryMul
    - [Int] tryDiv
    - [Int] tryMod
    - [Int] add
    - [Int] sub
    - [Int] mul
    - [Int] div
    - [Int] mod
    - [Int] sub
    - [Int] div
    - [Int] mod

 + [Lib] SafeERC20 
    - [Int] safeTransfer #
    - [Int] safeTransferFrom #
    - [Int] safeApprove #
    - [Int] safeIncreaseAllowance #
    - [Int] safeDecreaseAllowance #
    - [Prv] _callOptionalReturn #

 +  Initializable 
    - [Prv] _isConstructor

 +  WorldVesting (Initializable)
    - [Pub] initialize #
       - modifiers: initializer
    - [Ext] release #
    - [Pub] releasableAmount
    - [Pub] vestedAmount

 +  WorldOTC (Ownable)
    - [Pub]  #
    - [Pub] buy ($)
    - [Ext] getVestings
    - [Ext] getAllVestings
    - [Ext] getVestingsLength
    - [Ext] setRate #
       - modifiers: onlyOwner
    - [Ext] setVestingCliffDuration #
       - modifiers: onlyOwner
    - [Ext] setVestingDuration #
       - modifiers: onlyOwner
    - [Ext] setWhitelistedOnly #
       - modifiers: onlyOwner
    - [Ext] addToWhitelist #
       - modifiers: onlyOwner
    - [Ext] removeFromWhitelist #
       - modifiers: onlyOwner
    - [Pub] withdrawTokens #
       - modifiers: onlyOwner
    - [Pub] withdrawFunds #
       - modifiers: onlyOwner
    - [Ext]  ($)

							

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


// SPDX-License-Identifier: MIT

pragma solidity 0.7.4;

import "@openzeppelin/audits/token/ERC20/IERC20.sol";
import "@openzeppelin/audits/token/ERC20/SafeERC20.sol";
import "@openzeppelin/audits/math/SafeMath.sol";
import "@openzeppelin/audits/access/Ownable.sol";
import "@openzeppelin/audits/proxy/Clones.sol";
import "./WorldVesting.sol";

contract WorldOTC is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    IERC20 public immutable WORLD;
    address public immutable VESTING_LOGIC;

    mapping(address => address[]) public vestings;
    mapping(address => bool) public whitelisted;
    bool public whitelistedOnly = false;

    uint256 public rate;
    uint256 public vestingCliffDuration = 7 days;
    uint256 public vestingDuration = 28 days;

    constructor(address _world, address _vestingLogic, uint256 _rate) {
        require(_world != address(0), "WorldOTC: world is a zero address");
        require(_vestingLogic != address(0), "WorldOTC: vestingLogic is a zero address");
        require(_rate != 0, "WorldOTC: rate is zero");
        WORLD = IERC20(_world);
        VESTING_LOGIC = _vestingLogic;
        rate = _rate;
    }

    function buy() payable public {
        require(!whitelistedOnly || whitelisted[msg.sender], "WorldOTC: caller is not whitelisted");
        require(msg.value >= 1, "WorldOTC: eth value is less than 1");
        require((msg.value % 1 ether) == 0, "WorldOTC: eth value is not a whole number");

        uint256 balance = WORLD.balanceOf(address(this));
        uint256 amount = msg.value.mul(1e18).div(rate);
        require(amount <= balance, "WorldOTC: world balance is insufficient");

        WorldVesting vesting = WorldVesting(Clones.clone(VESTING_LOGIC));
        vesting.initialize(
            address(WORLD),
            msg.sender,
            rate,
            amount,
            block.timestamp,
            vestingCliffDuration,
            vestingDuration
        );

        WORLD.safeTransfer(address(vesting), amount);
        vestings[msg.sender].push(address(vesting));
    }

    function getVestings(address _account, uint256 _start, uint256 _length) external view returns (address[] memory) {
        address[] memory filteredVestings = new address[](_length);
        address[] memory accountVestings = vestings[_account];

        for (uint256 i = _start; i < _length; i++) {
            if (i == accountVestings.length) {
                break;
            }
            filteredVestings[i] = accountVestings[i];
        }

        return filteredVestings;
    }

    function getAllVestings(address _account) external view returns (address[] memory) {
        return vestings[_account];
    }

    function getVestingsLength(address _account) external view returns (uint256) {
        return vestings[_account].length;
    }

    function setRate(uint256 _rate) external onlyOwner {
        require(_rate != 0, "WorldOTC: rate is zero");
        rate = _rate;
    }

    function setVestingCliffDuration(uint256 _vestingCliffDuration) external onlyOwner {
        require(_vestingCliffDuration != 0, "WorldOTC: vestingCliffDuration is zero");
        require(_vestingCliffDuration <= vestingDuration, "WorldOTC: vestingCliffDuration is longer than vestingDuration");
        vestingCliffDuration = _vestingCliffDuration;
    }

    function setVestingDuration(uint256 _vestingDuration) external onlyOwner {
        require(_vestingDuration != 0, "WorldOTC: vestingDuration is zero");
        vestingDuration = _vestingDuration;
    }

    function setWhitelistedOnly(bool _whitelistedOnly) external onlyOwner {
        whitelistedOnly = _whitelistedOnly;
    }

    function addToWhitelist(address _account) external onlyOwner {
        require(_account != address(0), "WorldOTC: account is a zero address");
        whitelisted[_account] = true;
    }

    function removeFromWhitelist(address _account) external onlyOwner {
        require(_account != address(0), "WorldOTC: account is a zero address");
        whitelisted[_account] = false;
    }

    function withdrawTokens() public onlyOwner {
        uint256 worldBalance = WORLD.balanceOf(address(this));
        require(worldBalance != 0, "WorldOTC: no world tokens to withdraw");
        WORLD.safeTransfer(owner(), worldBalance);
    }

    function withdrawFunds() public onlyOwner {
        uint256 balance = address(this).balance;
        require(balance != 0, "WorldOTC: no funds to withdraw");
        payable(owner()).transfer(balance);
    }

    receive() external payable {
        buy();
    }
}


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



import "@openzeppelin/audits/token/ERC20/SafeERC20.sol";
import "@openzeppelin/audits/proxy/Initializable.sol";
import "@openzeppelin/audits/math/SafeMath.sol";

/**
 * This contract is based on open-zeppelin's TokenVesting.sol
 * (https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/master/audits/drafts/TokenVesting.sol)
 *
 * @title WorldVesting
 * A world token holder contract that can release its token balance gradually like a
 * typical vesting scheme, with a cliff and vesting period.
 */
contract WorldVesting is Initializable {
    // The vesting schedule is time-based (i.e. using block timestamps as opposed to e.g. block numbers), and is
    // therefore sensitive to timestamp manipulation (which is something miners can do, to a certain degree). Therefore,
    // it is recommended to avoid using short time durations (less than a minute). Typical vesting schemes, with a
    // cliff period of a year and a duration of four years, are safe to use.

    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    // beneficiary of world tokens after they are released
    address public beneficiary;

    // Durations and timestamps are expressed in UNIX time, the same units as block.timestamp.
    uint256 public cliff; // the cliff time of the world tokens vesting
    uint256 public start; // the start time of the token vesting
    uint256 public duration; // the duration of the world tokens vesting
    uint256 public released;  // the amount of the world tokens released
    uint256 public rate; // the eth rate per world token
    uint256 public amount; // the total amount of the world tokens vested

    IERC20 public world;

    /**
     * Initialize vesting contract that vests its balance of world tokens to the
     * beneficiary, gradually in a linear fashion until start + duration. By then all
     * of the balance will have vested.
     * @param _beneficiary address of the beneficiary to whom vested tokens are transferred
     * @param _rate eth rate per world token
     * @param _amount total amount of the world tokens vested
     * @param _cliffDuration duration in seconds of the cliff in which tokens will begin to vest
     * @param _start the time (as Unix time) at which point vesting starts
     * @param _duration duration in seconds of the period in which the tokens will vest
     */
    function initialize (
        address _world,
        address _beneficiary,
        uint256 _rate,
        uint256 _amount,
        uint256 _start,
        uint256 _cliffDuration,
        uint256 _duration
    ) public initializer {
        require(_world != address(0), "WorldVesting: world is a zero address");
        require(_beneficiary != address(0), "WorldVesting: beneficiary is a zero address");
        require(_rate > 0, "WorldVesting: rate is 0");
        require(_amount > 0, "WorldVesting: amount is 0");
        require(_cliffDuration <= _duration, "WorldVesting: cliff is longer than duration");
        require(_duration > 0, "WorldVesting: duration is 0");
        require(_start.add(_duration) > block.timestamp, "WorldVesting: final time is before current time");

        world = IERC20(_world);
        beneficiary = _beneficiary;
        rate = _rate;
        amount = _amount;
        duration = _duration;
        cliff = _start.add(_cliffDuration);
        start = _start;
    }

    /**
     * Transfers vested world tokens to beneficiary.
     */
    function release() external {
        uint256 unreleased = releasableAmount();

        require(unreleased > 0, "WorldVesting: no world tokens are due");

        released = released.add(unreleased);

        world.safeTransfer(beneficiary, unreleased);
    }

    /**
     * Calculates the amount that has already vested but hasn't been released yet.
     */
    function releasableAmount() public view returns (uint256) {
        return vestedAmount().sub(released);
    }

    /**
     * Calculates the amount that has already vested.
     */
    function vestedAmount() public view returns (uint256) {
        uint256 currentBalance = world.balanceOf(address(this));
        uint256 totalBalance = currentBalance.add(released);

        if (block.timestamp < cliff) {
            return 0;
        } else if (block.timestamp >= start.add(duration)) {
            return totalBalance;
        } else {
            return totalBalance.mul(block.timestamp.sub(start)).div(duration);
        }
    }
}




WorldBSC Contract


Smart Contract Graph

Contract Inheritance


 ($) = 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 #

 +  WorldBSC 
    - [Pub]  #
    - [Ext] swapWrappedWorldToWorld #
    - [Ext] swapWorldToWrappedWorld #

							

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


// SPDX-License-Identifier: MIT

pragma solidity 0.7.4;

import "@openzeppelin/audits/token/ERC20/IERC20.sol";

contract WorldBSC {

    IERC20 public immutable WORLD;
    IERC20 public immutable WRAPPED_WORLD;

    constructor(address _world, address _wrappedWorld) {
        require(_world != address(0), "WorldBSC: world is a zero address");
        require(_wrappedWorld != address(0), "WorldBSC: wrappedWorld is a zero address");

        WORLD = IERC20(_world);
        WRAPPED_WORLD = IERC20(_wrappedWorld);
    }

    function swapWrappedWorldToWorld(uint256 amount) external {
        require(amount > 0, "WorldBSC: input amount is zero");

        uint256 supply = WORLD.balanceOf(address(this));
        require(supply > 0, "WorldBSC: supply is zero");
        require(supply >= amount, "WorldBSC: supply is insufficient");

        uint256 balance = WRAPPED_WORLD.balanceOf(msg.sender);
        require(balance >= amount, "WorldBSC: caller's balance is insufficient");

        WRAPPED_WORLD.transferFrom(msg.sender, address(this), amount);
        WORLD.transfer(msg.sender, amount);
    }

    function swapWorldToWrappedWorld(uint256 amount) external {
        require(amount > 0, "WorldBSC: input amount is zero");

        uint256 supply = WRAPPED_WORLD.balanceOf(address(this));
        require(supply > 0, "WorldBSC: supply is zero");
        require(supply >= amount, "WorldBSC: supply is insufficient");

        uint256 balance = WORLD.balanceOf(msg.sender);
        require(balance >= amount, "WorldBSC: caller's balance is insufficient");

        WORLD.transferFrom(msg.sender, address(this), amount);
        WRAPPED_WORLD.transfer(msg.sender, amount);
    }
}