Fountain 合约解析

作者: uestcAries | 来源:发表于2018-10-30 14:19 被阅读64次

    大体来说, 合约分为如下几个模块:

    1: 合约逻辑控制分析、
    2: FTN源码部分分析、
    3: 合约安全性分析、
    4: 合约合理性分析、
    5:个人对FTN合约分析、

    fountain官网: https://fountainhub.com/

    image.png

    最近也在以太坊上看到部署了fountain ico的合约:https://etherscan.io/token/0x82cf44be0768a3600c4bdea58607783a3a7c51ae

    image.png

    fountain白皮书: https://www.jianshu.com/p/1a73af5a2eeb

    image.png

    上图可知fountain 已经转移了一部分代币到其他账户, 我们期待的FTN终于开始行动了, 不过作为我们个人似乎前面基本没戏进入私募轮, 所以我也只有期待A轮的公募

    那么白皮书提到了关于TOKEN 初始化分配已经后面的增发, 还有FP等等, 又如何从合约去体现呢? 那么下面我将仔细的来和大家聊一聊。

    fountain 合约代码:

    pragma solidity ^0.4.25;
    
    library SafeMath {
        function mul (uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
            uint256 c = a * b;
            assert(c / a == b);
            return c;
        }
    
        function div (uint256 a, uint256 b) internal pure returns (uint256) {
            return a / b;
        }
    
        function sub (uint256 a, uint256 b) internal pure returns (uint256) {
            assert(b <= a);
            return a - b;
        }
    
        function add (uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            assert(c >= a);
            return c;
        }
    }
    
    contract ERCBasic {
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        function totalSupply () public view returns (uint256);
        function balanceOf (address who) public view returns (uint256);
        function transfer (address to, uint256 value) public returns (bool);
    }
    
    contract ERC is ERCBasic {
        event Approval(address indexed owner, address indexed spender, uint256 value);
    
        function transferFrom (address from, address to, uint256 value) public returns (bool);
        function allowance (address owner, address spender) public view returns (uint256);
        function approve (address spender, uint256 value) public returns (bool);
    }
    
    contract Ownable {
        event OwnershipTransferred(address indexed oldone, address indexed newone);
        event FoundationOwnershipTransferred(address indexed oldFoundationOwner, address indexed newFoundationOwner);
    
        address internal owner;
        address internal foundationOwner;
    
        constructor () public {
            owner = msg.sender;
            foundationOwner = owner;
        }
    
        modifier onlyOwner () {
            require(msg.sender == owner);
            _;
        }
    
        modifier hasMintability () {
            require(msg.sender == owner || msg.sender == foundationOwner);
            _;
        }
    
        function transferOwnership (address newOwner) public returns (bool);
        
        function setFountainFoundationOwner (address foundation) public returns (bool);
    }
    
    contract Pausable is Ownable {
        event ContractPause();
        event ContractResume();
        event ContractPauseSchedule(uint256 from, uint256 to);
    
        uint256 internal pauseFrom;
        uint256 internal pauseTo;
    
        modifier whenRunning () {
            require(now < pauseFrom || now > pauseTo);
            _;
        }
    
        modifier whenPaused () {
            require(now >= pauseFrom && now <= pauseTo);
            _;
        }
    
        function pause () public onlyOwner {
            pauseFrom = now - 1;
            pauseTo = now + 30000 days;
            emit ContractPause();
        }
    
        function pause (uint256 from, uint256 to) public onlyOwner {
            require(to > from);
            pauseFrom = from;
            pauseTo = to;
            emit ContractPauseSchedule(from, to);
        }
    
        function resume () public onlyOwner {
            pauseFrom = now - 2;
            pauseTo = now - 1;
            emit ContractResume();
        }
    }
    
    contract TokenForge is Ownable {
        event ForgeStart();
        event ForgeStop();
    
        bool public forge_running = true;
    
        modifier canForge () {
            require(forge_running);
            _;
        }
    
        modifier cannotForge () {
            require(!forge_running);
            _;
        }
    
        function startForge () public onlyOwner cannotForge returns (bool) {
            forge_running = true;
            emit ForgeStart();
            return true;
        }
    
        function stopForge () public onlyOwner canForge returns (bool) {
            forge_running = false;
            emit ForgeStop();
            return true;
        }
    }
    
    contract CappedToken is Ownable {
        using SafeMath for uint256;
    
        uint256 public token_cap;
        uint256 public token_created;
        uint256 public token_foundation_cap;
        uint256 public token_foundation_created;
    
    
        constructor (uint256 _cap, uint256 _foundationCap) public {
            token_cap = _cap;
            token_foundation_cap = _foundationCap;
        }
    
        function changeCap (uint256 _cap) public onlyOwner returns (bool) {
            if (_cap < token_created && _cap > 0) return false;
            token_cap = _cap;
            return true;
        }
    
        function canMint (uint256 amount) public view returns (bool) {
            return (token_cap == 0) || (token_created.add(amount) <= token_cap);
        }
        
        function canMintFoundation(uint256 amount) internal view returns(bool) {
            return(token_foundation_created.add(amount) <= token_foundation_cap);
        }
    }
    
    contract BasicToken is ERCBasic, Pausable {
        using SafeMath for uint256;
    
        mapping(address => uint256) public wallets;
    
        modifier canTransfer (address _from, address _to, uint256 amount) {
            require((_from != address(0)) && (_to != address(0)));
            require(_from != _to);
            require(amount > 0);
            _;
        }
    
        function balanceOf (address user) public view returns (uint256) {
            return wallets[user];
        }
    }
    
    contract DelegatableToken is ERC, BasicToken {
        using SafeMath for uint256;
    
        mapping(address => mapping(address => uint256)) public warrants;
    
        function allowance (address owner, address delegator) public view returns (uint256) {
            return warrants[owner][delegator];
        }
    
        function approve (address delegator, uint256 value) public whenRunning returns (bool) {
            if (delegator == msg.sender) return true;
            warrants[msg.sender][delegator] = value;
            emit Approval(msg.sender, delegator, value);
            return true;
        }
    
        function increaseApproval (address delegator, uint256 delta) public whenRunning returns (bool) {
            if (delegator == msg.sender) return true;
            uint256 value = warrants[msg.sender][delegator].add(delta);
            warrants[msg.sender][delegator] = value;
            emit Approval(msg.sender, delegator, value);
            return true;
        }
    
        function decreaseApproval (address delegator, uint256 delta) public whenRunning returns (bool) {
            if (delegator == msg.sender) return true;
            uint256 value = warrants[msg.sender][delegator];
            if (value < delta) {
                value = 0;
            }
            else {
                value = value.sub(delta);
            }
            warrants[msg.sender][delegator] = value;
            emit Approval(msg.sender, delegator, value);
            return true;
        }
    }
    
    contract LockableProtocol is BasicToken {
        function invest (address investor, uint256 amount) public returns (bool);
        function getInvestedToken (address investor) public view returns (uint256);
        function getLockedToken (address investor) public view returns (uint256);
        function availableWallet (address user) public view returns (uint256) {
            return wallets[user].sub(getLockedToken(user));
        }
    }
    
    contract MintAndBurnToken is TokenForge, CappedToken, LockableProtocol {
        using SafeMath for uint256;
        
        event Mint(address indexed user, uint256 amount);
        event Burn(address indexed user, uint256 amount);
    
        constructor (uint256 _initial, uint256 _cap, uint256 _fountainCap) public CappedToken(_cap, _fountainCap) {
            token_created = _initial;
            wallets[msg.sender] = _initial;
    
            emit Mint(msg.sender, _initial);
            emit Transfer(address(0), msg.sender, _initial);
        }
    
        function totalSupply () public view returns (uint256) {
            return token_created;
        }
    
        function totalFountainSupply() public view returns(uint256) {
            return token_foundation_created;
        }
    
        function mint (address target, uint256 amount) public hasMintability whenRunning canForge returns (bool) {
            require(target != owner && target != foundationOwner); // Owner和FoundationOwner不能成为mint的对象
            require(canMint(amount));
    
            if (msg.sender == foundationOwner) {
                require(canMintFoundation(amount));
                token_foundation_created = token_foundation_created.add(amount);
            }
            
            token_created = token_created.add(amount);
            wallets[target] = wallets[target].add(amount);
    
            emit Mint(target, amount);
            emit Transfer(address(0), target, amount);
            return true;
        }
    
        function burn (uint256 amount) public whenRunning canForge returns (bool) {
            uint256 balance = availableWallet(msg.sender);
            require(amount <= balance);
    
            token_created = token_created.sub(amount);
            wallets[msg.sender] -= amount;
    
            emit Burn(msg.sender, amount);
            emit Transfer(msg.sender, address(0), amount);
    
            return true;
        }
    }
    
    contract LockableToken is MintAndBurnToken, DelegatableToken {
        using SafeMath for uint256;
    
        struct LockBin {
            uint256 start;
            uint256 finish;
            uint256 duration;
            uint256 amount;
        }
    
        event InvestStart();
        event InvestStop();
        event NewInvest(uint256 release_start, uint256 release_duration);
    
        uint256 public releaseStart;
        uint256 public releaseDuration;
        bool public forceStopInvest;
        mapping(address => mapping(uint => LockBin)) public lockbins;
    
        modifier canInvest () {
            require(!forceStopInvest);
            _;
        }
    
        constructor (uint256 _initial, uint256 _cap, uint256 _fountainCap) public MintAndBurnToken(_initial, _cap, _fountainCap) {
            forceStopInvest = true;
        }
    
        function pauseInvest () public onlyOwner whenRunning returns (bool) {
            require(!forceStopInvest);
            forceStopInvest = true;
            emit InvestStop();
            return true;
        }
    
        function resumeInvest () public onlyOwner whenRunning returns (bool) {
            require(forceStopInvest);
            forceStopInvest = false;
            emit InvestStart();
            return true;
        }
    
        function setInvest (uint256 release_start, uint256 release_duration) public onlyOwner whenRunning returns (bool) {
            releaseStart = release_start;
            releaseDuration = release_duration;
            forceStopInvest = false;
    
            emit NewInvest(release_start, release_duration);
            return true;
        }
    
        function invest (address investor, uint256 amount) public onlyOwner whenRunning canInvest returns (bool) {
            require(investor != address(0));
            require(investor != owner);
            require(investor != foundationOwner);
            require(amount > 0);
            require(canMint(amount));
    
            mapping(uint => LockBin) locks = lockbins[investor];
            LockBin storage info = locks[0];
            uint index = info.amount + 1;
            locks[index] = LockBin({
                start: releaseStart,
                finish: releaseStart + releaseDuration,
                duration: releaseDuration / (1 days),
                amount: amount
            });
            info.amount = index;
    
            token_created = token_created.add(amount);
            wallets[investor] = wallets[investor].add(amount);
            emit Mint(investor, amount);
            emit Transfer(address(0), investor, amount);
    
            return true;
        }
    
        function batchInvest (address[] investors, uint256 amount) public onlyOwner whenRunning canInvest returns (bool) {
            require(amount > 0);
    
            uint investorsLength = investors.length;
            uint investorsCount = 0;
            uint i;
            address r;
            for (i = 0; i < investorsLength; i ++) {
                r = investors[i];
                if (r == address(0) || r == owner || r == foundationOwner) continue;
                investorsCount ++;
            }
            require(investorsCount > 0);
    
            uint256 totalAmount = amount.mul(uint256(investorsCount));
            require(canMint(totalAmount));
    
            token_created = token_created.add(totalAmount);
    
            for (i = 0; i < investorsLength; i ++) {
                r = investors[i];
                if (r == address(0) || r == owner || r == foundationOwner) continue;
    
                mapping(uint => LockBin) locks = lockbins[r];
                LockBin storage info = locks[0];
                uint index = info.amount + 1;
                locks[index] = LockBin({
                    start: releaseStart,
                    finish: releaseStart + releaseDuration,
                    duration: releaseDuration / (1 days),
                    amount: amount
                });
                info.amount = index;
    
                wallets[r] = wallets[r].add(amount);
                emit Mint(r, amount);
                emit Transfer(address(0), r, amount);
            }
    
            return true;
        }
    
        function batchInvests (address[] investors, uint256[] amounts) public onlyOwner whenRunning canInvest returns (bool) {
            uint investorsLength = investors.length;
            require(investorsLength == amounts.length);
    
            uint investorsCount = 0;
            uint256 totalAmount = 0;
            uint i;
            address r;
            for (i = 0; i < investorsLength; i ++) {
                r = investors[i];
                if (r == address(0) || r == owner) continue;
                investorsCount ++;
                totalAmount += amounts[i];
            }
            require(totalAmount > 0);
            require(canMint(totalAmount));
    
            uint256 amount;
            token_created = token_created.add(totalAmount);
            for (i = 0; i < investorsLength; i ++) {
                r = investors[i];
                if (r == address(0) || r == owner) continue;
                amount = amounts[i];
                wallets[r] = wallets[r].add(amount);
                emit Mint(r, amount);
                emit Transfer(address(0), r, amount);
    
                mapping(uint => LockBin) locks = lockbins[r];
                LockBin storage info = locks[0];
                uint index = info.amount + 1;
                locks[index] = LockBin({
                    start: releaseStart,
                    finish: releaseStart + releaseDuration,
                    duration: releaseDuration / (1 days),
                    amount: amount
                });
                info.amount = index;
            }
    
            return true;
        }
    
        function getInvestedToken (address investor) public view returns (uint256) {
            require(investor != address(0) && investor != owner && investor != foundationOwner);
    
            mapping(uint => LockBin) locks = lockbins[investor];
            uint256 balance = 0;
            uint l = locks[0].amount;
            for (uint i = 1; i <= l; i ++) {
                LockBin memory bin = locks[i];
                balance = balance.add(bin.amount);
            }
            return balance;
        }
    
        function getLockedToken (address investor) public view returns (uint256) {
            require(investor != address(0) && investor != owner && investor != foundationOwner);
    
            mapping(uint => LockBin) locks = lockbins[investor];
            uint256 balance = 0;
            uint256 d = 1;
            uint l = locks[0].amount;
            for (uint i = 1; i <= l; i ++) {
                LockBin memory bin = locks[i];
                if (now <= bin.start) {
                    balance = balance.add(bin.amount);
                }
                else if (now < bin.finish) {
                    d = (now - bin.start) / (1 days);
                    balance = balance.add(bin.amount - bin.amount * d / bin.duration);
                }
            }
            return balance;
        }
    
        function canPay (address user, uint256 amount) internal view returns (bool) {
            uint256 balance = availableWallet(user);
            return amount <= balance;
        }
    
        function transfer (address target, uint256 value) public whenRunning canTransfer(msg.sender, target, value) returns (bool) {
            require(target != owner);
            require(canPay(msg.sender, value));
    
            wallets[msg.sender] = wallets[msg.sender].sub(value);
            wallets[target] = wallets[target].add(value);
            emit Transfer(msg.sender, target, value);
            return true;
        }
    
    
        function batchTransfer (address[] receivers, uint256 amount) public whenRunning returns (bool) {
            require(amount > 0);
    
            uint receiveLength = receivers.length;
            uint receiverCount = 0;
            uint i;
            address r;
            for (i = 0; i < receiveLength; i ++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                receiverCount ++;
            }
            require(receiverCount > 0);
    
            uint256 totalAmount = amount.mul(uint256(receiverCount));
            require(canPay(msg.sender, totalAmount));
    
            wallets[msg.sender] -= totalAmount;
            for (i = 0; i < receiveLength; i++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                wallets[r] = wallets[r].add(amount);
                emit Transfer(msg.sender, r, amount);
            }
            return true;
        }
    
        function batchTransfers (address[] receivers, uint256[] amounts) public whenRunning returns (bool) {
            uint receiveLength = receivers.length;
            require(receiveLength == amounts.length);
    
            uint receiverCount = 0;
            uint256 totalAmount = 0;
            uint i;
            address r;
            for (i = 0; i < receiveLength; i ++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                receiverCount ++;
                totalAmount += amounts[i];
            }
            require(totalAmount > 0);
            require(canPay(msg.sender, totalAmount));
    
            wallets[msg.sender] -= totalAmount;
            uint256 amount;
            for (i = 0; i < receiveLength; i++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                amount = amounts[i];
                if (amount == 0) continue;
                wallets[r] = wallets[r].add(amount);
                emit Transfer(msg.sender, r, amount);
            }
            return true;
        }
    
        function transferFrom (address from, address to, uint256 value) public whenRunning canTransfer(from, to, value) returns (bool) {
            require(from != owner);
            require(to != owner);
            require(canPay(from, value));
    
            uint256 warrant;
            if (msg.sender != from) {
                warrant = warrants[from][msg.sender];
                require(value <= warrant);
                warrants[from][msg.sender] = warrant.sub(value);
            }
    
            wallets[from] = wallets[from].sub(value);
            wallets[to] = wallets[to].add(value);
            emit Transfer(from, to, value);
            return true;
        }
    
        function batchTransferFrom (address from, address[] receivers, uint256 amount) public whenRunning returns (bool) {
            require(from != address(0) && from != owner);
            require(amount > 0);
    
            uint receiveLength = receivers.length;
            uint receiverCount = 0;
            uint i;
            address r;
            for (i = 0; i < receiveLength; i ++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                receiverCount ++;
            }
            require(receiverCount > 0);
    
            uint256 totalAmount = amount.mul(uint256(receiverCount));
            require(canPay(from, totalAmount));
    
            uint256 warrant;
            if (msg.sender != from) {
                warrant = warrants[from][msg.sender];
                require(totalAmount <= warrant);
                warrants[from][msg.sender] = warrant.sub(totalAmount);
            }
    
            wallets[from] -= totalAmount;
            for (i = 0; i < receiveLength; i++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                wallets[r] = wallets[r].add(amount);
                emit Transfer(from, r, amount);
            }
            return true;
        }
    
        function batchTransferFroms (address from, address[] receivers, uint256[] amounts) public whenRunning returns (bool) {
            require(from != address(0) && from != owner);
    
            uint receiveLength = receivers.length;
            require(receiveLength == amounts.length);
    
            uint receiverCount = 0;
            uint256 totalAmount = 0;
            uint i;
            address r;
            for (i = 0; i < receiveLength; i ++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                receiverCount ++;
                totalAmount += amounts[i];
            }
            require(totalAmount > 0);
            require(canPay(from, totalAmount));
    
            uint256 warrant;
            if (msg.sender != from) {
                warrant = warrants[from][msg.sender];
                require(totalAmount <= warrant);
                warrants[from][msg.sender] = warrant.sub(totalAmount);
            }
    
            wallets[from] -= totalAmount;
            uint256 amount;
            for (i = 0; i < receiveLength; i++) {
                r = receivers[i];
                if (r == address(0) || r == owner) continue;
                amount = amounts[i];
                if (amount == 0) continue;
                wallets[r] = wallets[r].add(amount);
                emit Transfer(from, r, amount);
            }
            return true;
        }
    }
    
    contract FountainToken is LockableToken {
        string  public constant name     = "Fountain";
        string  public constant symbol   = "FTN";
        uint8   public constant decimals = 18;
    
        uint256 private constant TOKEN_CAP     = 10000000000 * 10 ** uint256(decimals);
        uint256 private constant TOKEN_FOUNDATION_CAP = 300000000   * 10 ** uint256(decimals);
        uint256 private constant TOKEN_INITIAL = 0   * 10 ** uint256(decimals);
    
        constructor () public LockableToken(TOKEN_INITIAL, TOKEN_CAP, TOKEN_FOUNDATION_CAP) {
        }
    
        function suicide () public onlyOwner {
            selfdestruct(owner);
        }
    
        function transferOwnership (address newOwner) public onlyOwner returns (bool) {
            require(newOwner != address(0));
            require(newOwner != owner);
            require(newOwner != foundationOwner);
            require(wallets[owner] == 0);
            require(wallets[newOwner] == 0);
    
            address oldOwner = owner;
            owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
            
            return true;
        }
        
        function setFountainFoundationOwner (address newFoundationOwner) public onlyOwner returns (bool) {
            require(newFoundationOwner != address(0));
            require(newFoundationOwner != foundationOwner);
            require(newFoundationOwner != owner);
            require(wallets[newFoundationOwner] == 0);
    
            address oldFoundation = foundationOwner;
            foundationOwner = newFoundationOwner;
    
            emit FoundationOwnershipTransferred(oldFoundation, foundationOwner);
    
            uint256 all = wallets[oldFoundation];
            wallets[oldFoundation] -= all;
            wallets[newFoundationOwner] = all;
            emit Transfer(oldFoundation, newFoundationOwner, all);
    
            return true;
        }
        
    }
    

    1: 合约逻辑控制分析、

    1.1 合约控制还是非常细化,使用安全计算法进行加减乘除运算(SafeMath)来控制所有计算操作
    1.2 兼容官方基础 ERC20 代币协议, 也就是说能支持官方支持的钱包操作

    contract ERCBasic {
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        function totalSupply () public view returns (uint256);
        function balanceOf (address who) public view returns (uint256);
        function transfer (address to, uint256 value) public returns (bool);
    }
    

    1.3 合约可暂停

    contract Pausable is Ownable
    

    1.4 合约有自己独立的铸币厂

    contract TokenForge is Ownable
    

    1.5 铸币上限设置

    contract CappedToken is Ownable
    

    1.6 如何对FTN进行锁仓

    contract LockableProtocol is BasicToke
    

    1.7 FTN 代币主函数

    contract FountainToken is LockableToken {
        uint256 private constant TOKEN_CAP     = 10000000000 * 10 ** uint256(decimals);
        uint256 private constant TOKEN_FOUNDATION_CAP = 300000000   * 10 ** uint256(decimals);
        uint256 private constant TOKEN_INITIAL = 0   * 10 ** uint256(decimals);
    
        constructor () public LockableToken(TOKEN_INITIAL, TOKEN_CAP, TOKEN_FOUNDATION_CAP) {
        }
    }
    

    2: FTN源码部分分析、

       uint256 private constant TOKEN_CAP     = 10000000000 * 10 ** uint256(decimals);
    
          //TOKEN_CAP 说明这个FTN合约的增发上限, 不能超过这个值, 
          //后面这个函数看出始终是小于token_cap, 那么还得注意一点的是
          //token_cap 此处为0, 那么就说明FTN可以无限制的增发, 
          //那么这样和比特币就有很大的差距, 那么官方给出的是有限制的
    function canMint (uint256 amount) public view returns (bool) {
            return (token_cap == 0) || (token_created.add(amount) <= token_cap);
        }
       uint256 private constant TOKEN_FOUNDATION_CAP = 300000000   * 10 ** uint256(decimals);
        // fountain 基金会最大FTN
        function canMintFoundation(uint256 amount) internal view returns(bool) {
            return(token_foundation_created.add(amount) <= token_foundation_cap);
        }
    //说你基金会产生的不允许超过这个值, fountain 这个也是我比较满意的
    
        //FTN初始化0
        uint256 private constant TOKEN_INITIAL = 0   * 10 ** uint256(decimals);
    
    
    struct LockBin {
            uint256 start;  //当前轮募资资金解冻开始时间
            uint256 finish; // 当前轮募资解冻周期时长
            uint256 duration;//解锁周期
            uint256 amount; //FTN数量
        }
    //这个就比较重要 了, 这个可是保存了我们所有账户的FTN,
    function invest (address investor, uint256 amount) public onlyOwner whenRunning canInvest returns (bool) {
            require(investor != address(0));
            require(investor != owner); // 管理员不能参与募资
            require(investor != foundationOwner); // 基金会管理员也不行
            require(amount > 0);
            require(canMint(amount));
    
            mapping(uint => LockBin) locks = lockbins[investor];
            LockBin storage info = locks[0]; 
            uint index = info.amount + 1;
            locks[index] = LockBin({
                start: releaseStart,
                finish: releaseStart + releaseDuration,
                duration: releaseDuration / (1 days),
                amount: amount
            });
            info.amount = index;
            token_created = token_created.add(amount);
            wallets[investor] = wallets[investor].add(amount);
            emit Mint(investor, amount);
            emit Transfer(address(0), investor, amount);
    
            return true;
        }
    //上面的函数: 就记录了各位什么时间参与的FTN购买记录, 
    //这个也是保存在以太坊的链上, 解锁周期就是
    //每天解锁duration: releaseDuration / (1 days) 这个就记录了周期了
    
        function availableWallet (address user) public view returns (uint256) {
            return wallets[user].sub(getLockedToken(user));
        }
    //这个函数会告诉你,当前用户解锁了多少FTN, 解锁的才是可以交易的
    
    
    function mint (address target, uint256 amount) public hasMintability whenRunning canForge returns (bool) {
            require(target != owner && target != foundationOwner); // Owner和FoundationOwner不能成为mint的对象
            require(canMint(amount));
            if (msg.sender == foundationOwner) {
                require(canMintFoundation(amount));//做增发判断不能超过100亿
                token_foundation_created = token_foundation_created.add(amount);
            }
            token_created = token_created.add(amount);
            wallets[target] = wallets[target].add(amount); //FTN进入target这个账户了
    
            emit Mint(target, amount);
            emit Transfer(address(0), target, amount);
            return true;
        }
    //上面这个就是我最喜欢的函数了: 
    //增发函数, 可惜只有管理员有权限
    //(发钱的人不能用钱, 用钱的人不能自己增发钱, 所以这个逻辑还是比较合理)
    

    3: 合约安全性分析、

    以太坊ICO合约也看了很多, 目前FTN这个合约是我看的比较完整的源码, 从安全上来说, 合约使用SafeMath 库, 同时合约也支持合约的暂停, 退一万步来说, 有一天合约出现了问题, fountain官方也可销毁合约, 最大程解决了安全和利益最大化

    4: 合约合理性分析、

    1: 合约本身来说是对FTN有总量控制, 那么也就是说fountain 官方不可能无穷无尽的增发, 那么FTN会像比特币一样有价值
    2: 白皮书也借鉴了steem的转换机制, 以后FTN会变成FP(合约并未体现)

    5:个人对FTN合约分析

    FTN 合约很注重细节, 至于为什么, 简单的说说, 合约的逻辑, 增发FTN不能拥有FTN, 交易FTN者不增发FTN
    个人比较在意的是: 合约未来的扩展, 一旦合约出现问题, 如何来补丁合约, 还有就是合约的管理员权限过大, 大到瞬间可以成为亿万富豪, 所以fountain的合约管理员至关重要

    相关文章

      网友评论

      本文标题:Fountain 合约解析

      本文链接:https://www.haomeiwen.com/subject/tocgtqtx.html