// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "./lib/@openzeppelin/math/Math.sol"; import "./lib/@openzeppelin/token/ERC20/ERC20.sol"; import "./DeFiatGov.sol"; import "./DeFiatPoints.sol"; contract DeFiatToken is ERC20("DeFiat", "DFT") { //overrides the _transfer function and adds burn capabilities using SafeMath for uint; //== Variables == address private mastermind; // token creator. address public DeFiat_gov; // contract governing the Token address public DeFiat_points; // ERC20 loyalty TOKEN uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; struct Transaction { address sender; address recipient; uint256 burnRate; uint256 feeRate; address feeDestination; uint256 senderDiscount; uint256 recipientDiscount; uint256 actualDiscount; } Transaction private transaction; //== Modifiers == modifier onlyMastermind { require(msg.sender == mastermind, "only Mastermind"); _; } modifier onlyGovernor { require(msg.sender == mastermind || msg.sender == DeFiat_gov, "only Governance contract"); _; } //only Governance managing contract modifier onlyPoints { require(msg.sender == mastermind || msg.sender == DeFiat_points, " only Points contract"); _; } //only Points managing contract //== Events == event stdEvent(address _address, uint256 _number, bytes32 _signature, string _desc); //== Token generation == constructor (address _gov, address _points) public { //token requires that governance and points are up and running mastermind = msg.sender; _mint(mastermind, 1e18 * 500000); //mint 300,000 tokens DeFiat_gov = _gov; // contract governing the Token DeFiat_points = _points; // ERC20 loyalty TOKEN } //== mastermind == function killContract() public onlyMastermind { selfdestruct(msg.sender); //destroys the contract } // TESTNET only Mastermind can kill contract function widthdrawAnyToken(address _recipient, address _ERC20address, uint256 _amount) public onlyGovernor returns (bool) { IERC20(_ERC20address).transfer(_recipient, _amount); //use of the _ERC20 traditional transfer return true; } //get tokens sent by error to contract function setGovernorContract(address _gov) external onlyGovernor { DeFiat_gov = _gov; } // -> governance transfer function setPointsContract(address _pts) external onlyGovernor { DeFiat_points = _pts; } // -> new points management contract function setMastermind(address _mastermind) external onlyMastermind { mastermind = _mastermind; //use the 0x0 address to resign } //== View variables from external contracts == function _viewFeeRate() public view returns(uint256){ return DeFiatGov(DeFiat_gov).viewFeeRate(); } function _viewBurnRate() public view returns(uint256){ return DeFiatGov(DeFiat_gov).viewBurnRate(); } function _viewFeeDestination() public view returns(address){ return DeFiatGov(DeFiat_gov).viewFeeDestination(); } function _viewDiscountOf(address _address) public view returns(uint256){ return DeFiatPoints(DeFiat_points).viewDiscountOf(_address); } function _viewPointsOf(address _address) public view returns(uint256){ return DeFiatPoints(DeFiat_points).balanceOf(_address); } //== override _transfer function in the ERC20Simple contract == function updateTxStruct(address sender, address recipient) internal returns(bool){ transaction.sender = sender; transaction.recipient = recipient; transaction.burnRate = _viewBurnRate(); transaction.feeRate = _viewFeeRate(); transaction.feeDestination = _viewFeeDestination(); transaction.senderDiscount = _viewDiscountOf(sender); transaction.recipientDiscount = _viewDiscountOf(recipient); transaction.actualDiscount = Math.max(transaction.senderDiscount, transaction.recipientDiscount); if (transaction.actualDiscount > 100) { transaction.actualDiscount = 100; } //manages "forever pools" return true; } //struct used to prevent "stack too deep" error function addPoints(address sender, uint256 _amount) public { DeFiatPoints(DeFiat_points).addPoints(sender, _amount, 1e18); //Update user's loyalty points +1 = +1e18 } function _transfer(address sender, address recipient, uint256 amount) internal override { //overrides the inherited ERC20 _transfer require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); //load transaction Struct (gets info from external contracts) updateTxStruct(sender, recipient); //get discounts and apply them. You get the MAX discounts of the sender x recipient. discount is base100 // amount discounted to calculate fees uint256 dAmount = SafeMath.div(SafeMath.mul(amount, SafeMath.sub(100, transaction.actualDiscount)), 100); //Calculates burn and fees on discounted amount (burn and fees are 0.0X% ie base 10000) uint _toBurn = SafeMath.div(SafeMath.mul(dAmount,transaction.burnRate),10000); uint _toFee = SafeMath.div(SafeMath.mul(dAmount,transaction.feeRate),10000); uint _amount = SafeMath.sub(amount, SafeMath.add(_toBurn,_toFee)); //calculates the remaning amount to be sent //transfers -> forcing _ERC20 level if(_toFee > 0) { ERC20._transfer(sender, transaction.feeDestination, _toFee); //native _transfer + emit } //transfer fee if(_toBurn > 0) { ERC20._burn(sender,_toBurn); } //native _burn tokens from sender //transfer remaining amount. + emit ERC20._transfer(sender, recipient, _amount); //native _transfer + emit //mint loyalty points and update lastTX if(sender != recipient){ addPoints(sender, amount); } //uses the full amount to determine point minting } function burn(uint256 _amount) public returns (bool) { ERC20._burn(msg.sender, _amount); } }