美文网首页
首个STO项目 - tZERO源码分享

首个STO项目 - tZERO源码分享

作者: 东方泯 | 来源:发表于2018-10-29 18:29 被阅读0次

    最近STO成为了新的热点,赶紧跟上节奏看看。

    今天分享的是首个STO项目 - tZERO的源码,该合约地址为0xc4BF277257C140A799b785C6C5096c6Da7ef6A62,ERC20合约。

    pragma solidity >=0.4.24 <0.5.0;
    
    /**
     *
     *  @title AddressMap
     *  @dev Map of unique indexed addresseses.
     *
     *  **NOTE**
     *    The internal collections are one-based.
     *    This is simply because null values are expressed as zero,
     *    which makes it hard to check for the existence of items within the array,
     *    or grabbing the first item of an array for non-existent items.
     *
     *    This is only exposed internally, so callers still use zero-based indices.
     *
     */
    library AddressMap {
        address constant ZERO_ADDRESS = address(0);
    
        struct Data {
            int256 count;
            mapping(address => int256) indices;
            mapping(int256 => address) items;
        }
    
        /**
         *  Appends the address to the end of the map, if the addres is not
         *  zero and the address doesn't currently exist.
         *  @param addr The address to append.
         *  @return true if the address was added.
         */
        function append(Data storage self, address addr)
        internal
        returns (bool) {
            if (addr == ZERO_ADDRESS) {
                return false;
            }
    
            int256 index = self.indices[addr] - 1;
            if (index >= 0 && index < self.count) {
                return false;
            }
    
            self.count++;
            self.indices[addr] = self.count;
            self.items[self.count] = addr;
            return true;
        }
    
        /**
         *  Removes the given address from the map.
         *  @param addr The address to remove from the map.
         *  @return true if the address was removed.
         */
        function remove(Data storage self, address addr)
        internal
        returns (bool) {
            int256 oneBasedIndex = self.indices[addr];
            if (oneBasedIndex < 1 || oneBasedIndex > self.count) {
                return false;  // address doesn't exist, or zero.
            }
    
            // When the item being removed is not the last item in the collection,
            // replace that item with the last one, otherwise zero it out.
            //
            //  If {2} is the item to be removed
            //     [0, 1, 2, 3, 4]
            //  The result would be:
            //     [0, 1, 4, 3]
            //
            if (oneBasedIndex < self.count) {
                // Replace with last item
                address last = self.items[self.count];  // Get the last item
                self.indices[last] = oneBasedIndex;     // Update last items index to current index
                self.items[oneBasedIndex] = last;       // Update current index to last item
                delete self.items[self.count];          // Delete the last item, since it's moved
            } else {
                // Delete the address
                delete self.items[oneBasedIndex];
            }
    
            delete self.indices[addr];
            self.count--;
            return true;
        }
    
        /**
         *  Retrieves the address at the given index.
         *  THROWS when the index is invalid.
         *  @param index The index of the item to retrieve.
         *  @return The address of the item at the given index.
         */
        function at(Data storage self, int256 index)
        internal
        view
        returns (address) {
            require(index >= 0 && index < self.count, "Index outside of bounds.");
            return self.items[index + 1];
        }
    
        /**
         *  Gets the index of the given address.
         *  @param addr The address of the item to get the index for.
         *  @return The index of the given address.
         */
        function indexOf(Data storage self, address addr)
        internal
        view
        returns (int256) {
            if (addr == ZERO_ADDRESS) {
                return -1;
            }
    
            int256 index = self.indices[addr] - 1;
            if (index < 0 || index >= self.count) {
                return -1;
            }
            return index;
        }
    
        /**
         *  Returns whether or not the given address exists within the map.
         *  @param addr The address to check for existence.
         *  @return If the given address exists or not.
         */
        function exists(Data storage self, address addr)
        internal
        view
        returns (bool) {
            int256 index = self.indices[addr] - 1;
            return index >= 0 && index < self.count;
        }
    
        /**
         * Clears all items within the map.
         */
        function clear(Data storage self)
        internal {
            self.count = 0;
        }
    
    }
    
    /**
     *
     *  @title AccountMap
     *  @dev Map of unique indexed accounts.
     *
     *  **NOTE**
     *    The internal collections are one-based.
     *    This is simply because null values are expressed as zero,
     *    which makes it hard to check for the existence of items within the array,
     *    or grabbing the first item of an array for non-existent items.
     *
     *    This is only exposed internally, so callers still use zero-based indices.
     *
     */
    library AccountMap {
        address constant ZERO_ADDRESS = address(0);
    
        struct Account {
            address addr;
            uint8 kind;
            bool frozen;
            address parent;
        }
    
        struct Data {
            int256 count;
            mapping(address => int256) indices;
            mapping(int256 => Account) items;
        }
    
        /**
         *  Appends the address to the end of the map, if the addres is not
         *  zero and the address doesn't currently exist.
         *  @param addr The address to append.
         *  @return true if the address was added.
         */
        function append(Data storage self, address addr, uint8 kind, bool isFrozen, address parent)
        internal
        returns (bool) {
            if (addr == ZERO_ADDRESS) {
                return false;
            }
    
            int256 index = self.indices[addr] - 1;
            if (index >= 0 && index < self.count) {
                return false;
            }
    
            self.count++;
            self.indices[addr] = self.count;
            self.items[self.count] = Account(addr, kind, isFrozen, parent);
            return true;
        }
    
        /**
         *  Removes the given address from the map.
         *  @param addr The address to remove from the map.
         *  @return true if the address was removed.
         */
        function remove(Data storage self, address addr)
        internal
        returns (bool) {
            int256 oneBasedIndex = self.indices[addr];
            if (oneBasedIndex < 1 || oneBasedIndex > self.count) {
                return false;  // address doesn't exist, or zero.
            }
    
            // When the item being removed is not the last item in the collection,
            // replace that item with the last one, otherwise zero it out.
            //
            //  If {2} is the item to be removed
            //     [0, 1, 2, 3, 4]
            //  The result would be:
            //     [0, 1, 4, 3]
            //
            if (oneBasedIndex < self.count) {
                // Replace with last item
                Account storage last = self.items[self.count];  // Get the last item
                self.indices[last.addr] = oneBasedIndex;        // Update last items index to current index
                self.items[oneBasedIndex] = last;               // Update current index to last item
                delete self.items[self.count];                  // Delete the last item, since it's moved
            } else {
                // Delete the account
                delete self.items[oneBasedIndex];
            }
    
            delete self.indices[addr];
            self.count--;
            return true;
        }
    
        /**
         *  Retrieves the address at the given index.
         *  THROWS when the index is invalid.
         *  @param index The index of the item to retrieve.
         *  @return The address of the item at the given index.
         */
        function at(Data storage self, int256 index)
        internal
        view
        returns (Account) {
            require(index >= 0 && index < self.count, "Index outside of bounds.");
            return self.items[index + 1];
        }
    
        /**
         *  Gets the index of the given address.
         *  @param addr The address of the item to get the index for.
         *  @return The index of the given address.
         */
        function indexOf(Data storage self, address addr)
        internal
        view
        returns (int256) {
            if (addr == ZERO_ADDRESS) {
                return -1;
            }
    
            int256 index = self.indices[addr] - 1;
            if (index < 0 || index >= self.count) {
                return -1;
            }
            return index;
        }
    
        /**
         *  Gets the Account for the given address.
         *  THROWS when an account doesn't exist for the given address.
         *  @param addr The address of the item to get.
         *  @return The account of the given address.
         */
        function get(Data storage self, address addr)
        internal
        view
        returns (Account) {
            return at(self, indexOf(self, addr));
        }
    
        /**
         *  Returns whether or not the given address exists within the map.
         *  @param addr The address to check for existence.
         *  @return If the given address exists or not.
         */
        function exists(Data storage self, address addr)
        internal
        view
        returns (bool) {
            int256 index = self.indices[addr] - 1;
            return index >= 0 && index < self.count;
        }
    
        /**
         * Clears all items within the map.
         */
        function clear(Data storage self)
        internal {
            self.count = 0;
        }
    
    }
    
    /**
     *  @title Ownable
     *  @dev Provides a modifier that requires the caller to be the owner of the contract.
     */
    contract Ownable {
        address public owner;
    
        event OwnerTransferred(
            address indexed oldOwner,
            address indexed newOwner
        );
    
        constructor() public {
            owner = msg.sender;
        }
    
        modifier onlyOwner() {
            require(msg.sender == owner, "Owner account is required");
            _;
        }
    
        /**
         * @dev Allows the current owner to transfer control of the contract to newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwner(address newOwner)
        public
        onlyOwner {
            require(newOwner != owner, "New Owner cannot be the current owner");
            require(newOwner != address(0), "New Owner cannot be zero address");
            address prevOwner = owner;
            owner = newOwner;
            emit OwnerTransferred(prevOwner, newOwner);
        }
    }
    
    /**
     *  @title Lockable
     *  @dev The Lockable contract adds the ability for the contract owner to set the lock status
     *  of the account. A modifier is provided that checks the throws when the contract is
     *  in the locked state.
     */
    contract Lockable is Ownable {
        bool public isLocked;
    
        constructor() public {
            isLocked = false;
        }
    
        modifier isUnlocked() {
            require(!isLocked, "Contract is currently locked for modification");
            _;
        }
    
        /**
         *  Set the contract to a read-only state.
         *  @param locked The locked state to set the contract to.
         */
        function setLocked(bool locked)
        onlyOwner
        external {
            require(isLocked != locked, "Contract already in requested lock state");
    
            isLocked = locked;
        }
    }
    
    /**
     *  @title Destroyable
     *  @dev The Destroyable contract alows the owner address to `selfdestruct` the contract.
     */
    contract Destroyable is Ownable {
        /**
         *  Allow the owner to destroy this contract.
         */
        function kill()
        onlyOwner
        external {
            selfdestruct(owner);
        }
    }
    
    /**
     *  Contract to facilitate locking and self destructing.
     */
    contract LockableDestroyable is Lockable, Destroyable { }
    
    /**
     *  @title Registry Storage
     */
    contract Storage is Ownable, LockableDestroyable {
        struct Mapping {
            address key;
            address value;
        }
    
        using AccountMap for AccountMap.Data;
        using AddressMap for AddressMap.Data;
    
        // ------------------------------- Variables -------------------------------
        // Nmber of data slots available for accounts
        uint8 MAX_DATA = 30;
    
        // Accounts
        AccountMap.Data public accounts;
    
        // Account Data
        //   - mapping of:
        //     (address        => (index =>    data))
        mapping(address => mapping(uint8 => bytes32)) public data;
    
        // Address write permissions
        //     (kind  => address)
        mapping(uint8 => AddressMap.Data) public permissions;
    
    
        // ------------------------------- Modifiers -------------------------------
        /**
         *  Ensures the `msg.sender` has permission for the given kind/type of account.
         *  
         *    - The `owner` account is always allowed
         *    - Addresses/Contracts must have a corresponding entry, for the given kind
         */
        modifier isAllowed(uint8 kind) {
            require(kind > 0, "Invalid, or missing permission");
            if (msg.sender != owner) {
                require(permissions[kind].exists(msg.sender), "Missing permission");
            }
            _;
        }
    
    
        // ---------------------------- Address Getters ----------------------------
        /**
         *  Gets the account at the given index
         *  THROWS when the index is out-of-bounds
         *  @param index The index of the item to retrieve
         *  @return The address, kind, frozen status, and parent of the account at the given index
         */
        function accountAt(int256 index)
        external
        view
        returns(address, uint8, bool, address) {
            AccountMap.Account memory acct = accounts.at(index);
            return (acct.addr, acct.kind, acct.frozen, acct.parent);
        }
    
        /**
         *  Gets the account for the given address
         *  THROWS when the account doesn't exist
         *  @param addr The address of the item to retrieve
         *  @return The address, kind, frozen status, and parent of the account at the given index
         */
        function accountGet(address addr)
        external
        view
        returns(uint8, bool, address) {
            AccountMap.Account memory acct = accounts.get(addr);
            return (acct.kind, acct.frozen, acct.parent);
        }
    
        /**
         *  Gets the parent address for the given account address
         *  THROWS when the account doesn't exist
         *  @param addr The address of the account
         *  @return The parent address
         */
        function accountParent(address addr)
        external
        view
        returns(address) {
            return accounts.get(addr).parent;
        }
    
        /**
         *  Gets the account kind, for the given account address
         *  THROWS when the account doesn't exist
         *  @param addr The address of the account
         *  @return The kind of account
         */
        function accountKind(address addr)
        external
        view
        returns(uint8) {
            return accounts.get(addr).kind;
        }
    
        /**
         *  Gets the frozen status of the account
         *  THROWS when the account doesn't exist
         *  @param addr The address of the account
         *  @return The frozen status of the account
         */
        function accountFrozen(address addr)
        external
        view
        returns(bool) {
            return accounts.get(addr).frozen;
        }
    
        /**
         *  Gets the index of the account
         *  Returns -1 for missing accounts
         *  @param addr The address of the account to get the index for
         *  @return The index of the given account address
         */
        function accountIndexOf(address addr)
        external
        view
        returns(int256) {
            return accounts.indexOf(addr);
        }
    
        /**
         *  Returns wether or not the given address exists
         *  @param addr The account address
         *  @return If the given address exists
         */
        function accountExists(address addr)
        external
        view
        returns(bool) {
            return accounts.exists(addr);
        }
    
        /**
         *  Returns wether or not the given address exists for the given kind
         *  @param addr The account address
         *  @param kind The kind of address
         *  @return If the given address exists with the given kind
         */
        function accountExists(address addr, uint8 kind)
        external
        view
        returns(bool) {
            int256 index = accounts.indexOf(addr);
            if (index < 0) {
                return false;
            }
            return accounts.at(index).kind == kind;
        }
    
    
        // -------------------------- Permission Getters ---------------------------
        /**
         *  Retrieves the permission address at the index for the given type
         *  THROWS when the index is out-of-bounds
         *  @param kind The kind of permission
         *  @param index The index of the item to retrieve
         *  @return The permission address of the item at the given index
         */
        function permissionAt(uint8 kind, int256 index)
        external
        view
        returns(address) {
            return permissions[kind].at(index);
        }
    
        /**
         *  Gets the index of the permission address for the given type
         *  Returns -1 for missing permission
         *  @param kind The kind of perission
         *  @param addr The address of the permission to get the index for
         *  @return The index of the given permission address
         */
        function permissionIndexOf(uint8 kind, address addr)
        external
        view
        returns(int256) {
            return permissions[kind].indexOf(addr);
        }
    
        /**
         *  Returns wether or not the given permission address exists for the given type
         *  @param kind The kind of permission
         *  @param addr The address to check for permission
         *  @return If the given address has permission or not
         */
        function permissionExists(uint8 kind, address addr)
        external
        view
        returns(bool) {
            return permissions[kind].exists(addr);
        }
    
        // -------------------------------------------------------------------------
    
        /**
         *  Adds an account to storage
         *  THROWS when `msg.sender` doesn't have permission
         *  THROWS when the account already exists
         *  @param addr The address of the account
         *  @param kind The kind of account
         *  @param isFrozen The frozen status of the account
         *  @param parent The account parent/owner
         */
        function addAccount(address addr, uint8 kind, bool isFrozen, address parent)
        isUnlocked
        isAllowed(kind)
        external {
            require(accounts.append(addr, kind, isFrozen, parent), "Account already exists");
        }
    
        /**
         *  Sets an account's frozen status
         *  THROWS when the account doesn't exist
         *  @param addr The address of the account
         *  @param frozen The frozen status of the account
         */
        function setAccountFrozen(address addr, bool frozen)
        isUnlocked
        isAllowed(accounts.get(addr).kind)
        external {
            // NOTE: Not bounds checking `index` here, as `isAllowed` ensures the address exists.
            //       Indices are one-based internally, so we need to add one to compensate.
            int256 index = accounts.indexOf(addr) + 1;
            accounts.items[index].frozen = frozen;
        }
    
        /**
         *  Removes an account from storage
         *  THROWS when the account doesn't exist
         *  @param addr The address of the account
         */
        function removeAccount(address addr)
        isUnlocked
        isAllowed(accounts.get(addr).kind)
        external {
            bytes32 ZERO_BYTES = bytes32(0);
            mapping(uint8 => bytes32) accountData = data[addr];
    
            // Remove data
            for (uint8 i = 0; i < MAX_DATA; i++) {
                if (accountData[i] != ZERO_BYTES) {
                    delete accountData[i];
                }
            }
    
            // Remove account
            accounts.remove(addr);
        }
    
        /**
         *  Sets data for an address/caller
         *  THROWS when the account doesn't exist
         *  @param addr The address
         *  @param index The index of the data
         *  @param customData The data store set
         */
        function setAccountData(address addr, uint8 index, bytes32 customData)
        isUnlocked
        isAllowed(accounts.get(addr).kind)
        external {
            require(index < MAX_DATA, "index outside of bounds");
            data[addr][index] = customData;
        }
    
        /**
         *  Grants the address permission for the given kind
         *  @param kind The kind of address
         *  @param addr The address
         */
        function grantPermission(uint8 kind, address addr)
        isUnlocked
        isAllowed(kind)
        external {
            permissions[kind].append(addr);
        }
    
        /**
         *  Revokes the address permission for the given kind
         *  @param kind The kind of address
         *  @param addr The address
         */
        function revokePermission(uint8 kind, address addr)
        isUnlocked
        isAllowed(kind)
        external {
            permissions[kind].remove(addr);
        }
    
    }
    
    interface ERC20 {
        event Approval(address indexed owner, address indexed spender, uint256 value);
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        function allowance(address owner, address spender) external view returns (uint256);
        function approve(address spender, uint256 value) external returns (bool);
        function balanceOf(address who) external view returns (uint256);
        function totalSupply() external view returns (uint256);
        function transfer(address to, uint256 value) external returns (bool);
        function transferFrom(address from, address to, uint256 value) external returns (bool);
    }
    
    library AdditiveMath {
        /**
         *  Adds two numbers and returns the result
         *  THROWS when the result overflows
         *  @return The sum of the arguments
         */
        function add(uint256 x, uint256 y)
        internal
        pure
        returns (uint256) {
            uint256 sum = x + y;
            require(sum >= x, "Results in overflow");
            return sum;
        }
    
        /**
         *  Subtracts two numbers and returns the result
         *  THROWS when the result underflows
         *  @return The difference of the arguments
         */
        function subtract(uint256 x, uint256 y)
        internal
        pure
        returns (uint256) {
            require(y <= x, "Results in underflow");
            return x - y;
        }
    }
    
    interface ComplianceRule {
    
        /**
         * @param from The address of the sender
         * @param to The address of the receiver
         * @param toKind The kind of the to address
         * @param store The Storage contract
         * @return true if transfer is allowed
         */
        function canTransfer(address from, address to, uint8 toKind, Storage store)
        external
        view
        returns(bool);
    }
    
    interface Compliance {
    
        /**
         * This event is emitted when an address's frozen status has changed.
         * @param addr The address whose frozen status has been updated.
         * @param isFrozen Whether the custodian is being frozen.
         * @param owner The address that updated the frozen status.
         */
        event AddressFrozen(
            address indexed addr,
            bool indexed isFrozen,
            address indexed owner
        );
    
        /**
         *  Sets an address frozen status for this token
         *  @param addr The address to update frozen status.
         *  @param freeze Frozen status of the address.
         */
        function setAddressFrozen(address addr, bool freeze)
        external;
    
        /**
         *  Returns all of the current compliance rules for this token
         *  @param kind The bucket of rules to get.
         *  @return List of all compliance rules.
         */
        function getRules(uint8 kind)
        view
        external
        returns(ComplianceRule[]);
    
        /**
         *  Replaces all of the existing rules with the given ones
         *  @param kind The bucket of rules to set.
         *  @param rules New compliance rules.
         */
        function setRules(uint8 kind, ComplianceRule[] rules)
        external;
    
        /**
         *  Checks if a transfer can occur between the from/to addresses.
         *  Both addressses must be valid, unfrozen, and pass all compliance rule checks.
         *  @param from The address of the sender.
         *  @param to The address of the receiver.
         *  @return If a transfer can occure between the from/to addresses.
         */
        function canTransfer(address from, address to)
        view
        external
        returns(bool);
    
    }
    
    contract T0ken is ERC20, Ownable, LockableDestroyable {
        // ------------------------------- Variables -------------------------------
        using AdditiveMath for uint256;
    
        using AddressMap for AddressMap.Data;
        AddressMap.Data public shareholders;
    
        mapping(address => address) public cancellations;
        mapping(address => uint256) internal balances;
        mapping (address => mapping (address => uint256)) private allowed;
    
        address public issuer;
        bool public issuingFinished = false;
        uint256 internal totalSupplyTokens;
        address constant internal ZERO_ADDRESS = address(0);
        Compliance public compliance;
        Storage public store;
    
        // Possible 3rd party integration variables
        string public constant name = "TZERO PREFERRED";
        string public constant symbol = "TZROP";
        uint8 public constant decimals = 0;
    
        // ------------------------------- Modifiers -------------------------------
        modifier transferCheck(uint256 value, address fromAddr) {
            require(value <= balances[fromAddr], "Balance is more than from address has");
            _;
        }
    
        modifier isNotCancelled(address addr) {
            require(cancellations[addr] == ZERO_ADDRESS, "Address has been cancelled");
            _;
        }
    
        modifier onlyIssuer() {
            require(msg.sender == issuer, "Only issuer allowed");
            _;
        }
    
        modifier canIssue() {
            require(!issuingFinished, "Issuing is already finished");
            _;
        }
    
        modifier canTransfer(address fromAddress, address toAddress) {
            if(fromAddress == issuer) {
                require(store.accountExists(toAddress), "The to address does not exist");
            }
            else {
                require(compliance.canTransfer(fromAddress, toAddress), "Address cannot transfer");
            }
            _;
        }
    
        modifier canTransferFrom(address fromAddress, address toAddress) {
            if(msg.sender == owner) {
                require(store.accountExists(toAddress), "The to address does not exist");
            }
            else {
                require(compliance.canTransfer(fromAddress, toAddress), "Address cannot transfer");
            }
            _;
        }
    
        // -------------------------- Events -------------------------------
    
        /**
         *  This event is emitted when an address is cancelled and replaced with
         *  a new address.  This happens in the case where a shareholder has
         *  lost access to their original address and needs to have their share
         *  reissued to a new address.  This is the equivalent of issuing replacement
         *  share certificates.
         *  @param original The address being superseded.
         *  @param replacement The new address.
         *  @param sender The address that caused the address to be superseded.
        */
        event VerifiedAddressSuperseded(address indexed original, address indexed replacement, address indexed sender);
        event IssuerSet(address indexed previousIssuer, address indexed newIssuer);
        event Issue(address indexed to, uint256 amount);
        event IssueFinished();
    
    
        // ---------------------------- Getters ----------------------------
    
        /**
        * @return total number of tokens in existence
        */
        function totalSupply()
        external
        view
        returns (uint256) {
            return totalSupplyTokens;
        }
    
        /**
        * @dev Gets the balance of the specified address.
        * @param addr The address to query the the balance of.
        * @return An uint256 representing the amount owned by the passed address.
        */
        function balanceOf(address addr)
        external
        view
        returns (uint256) {
            return balances[addr];
        }
    
        /**
         * @dev Function to check the amount of tokens that an owner allowed to a spender.
         * @param addrOwner address The address which owns the funds.
         * @param spender address The address which will spend the funds.
         * @return A uint256 specifying the amount of tokens still available for the spender.
         */
        function allowance(address addrOwner, address spender)
        isUnlocked
        external
        view
        returns (uint256) {
            return allowed[addrOwner][spender];
        }
    
        /**
         *  By counting the number of token holders using `holderCount`
         *  you can retrieve the complete list of token holders, one at a time.
         *  It MUST throw if `index >= holderCount()`.
         *  @param index The zero-based index of the holder.
         *  @return the address of the token holder with the given index.
         */
        function holderAt(int256 index)
        external
        view
        returns (address){
            return shareholders.at(index);
        }
    
        /**
         *  Checks to see if the supplied address is a share holder.
         *  @param addr The address to check.
         *  @return true if the supplied address owns a token.
         */
        function isHolder(address addr)
        external
        view
        returns (bool) {
            return shareholders.exists(addr);
        }
    
        /**
         *  Checks to see if the supplied address was superseded.
         *  @param addr The address to check.
         *  @return true if the supplied address was superseded by another address.
         */
        function isSuperseded(address addr)
        onlyOwner
        external
        view
        returns (bool) {
            return cancellations[addr] != ZERO_ADDRESS;
        }
    
        /**
         *  Gets the most recent address, given a superseded one.
         *  Addresses may be superseded multiple times, so this function needs to
         *  follow the chain of addresses until it reaches the final, verified address.
         *  @param addr The superseded address.
         *  @return the verified address that ultimately holds the share.
         */
        function getSuperseded(address addr)
        onlyOwner
        public
        view
        returns (address) {
            require(addr != ZERO_ADDRESS, "Non-zero address required");
            address candidate = cancellations[addr];
            if (candidate == ZERO_ADDRESS) {
                return ZERO_ADDRESS;
            }
            return candidate;
        }
    
        // -----------------------------------------------------------------
    
        function setCompliance(address newComplianceAddress)
        isUnlocked
        onlyOwner
        external {
            compliance = Compliance(newComplianceAddress);
        }
    
        function setStorage(Storage s)
        isUnlocked
        onlyOwner
        external {
            store = s;
        }
    
        /**
        * @dev transfer token for a specified address
        * @param to The address to transfer to.
        * @param value The amount to be transferred.
        *  The `transfer` function MUST NOT allow transfers to addresses that
        *  have not been verified and added to the contract.
        *  If the `to` address is not currently a shareholder then it MUST become one.
        *  If the transfer will reduce `msg.sender`'s balance to 0 then that address
        *  MUST be removed from the list of shareholders.
        */
        function transfer(address to, uint256 value)
        isUnlocked
        isNotCancelled(to)
        transferCheck(value, msg.sender)
        canTransfer(msg.sender, to)
        public
        returns (bool) {
            balances[msg.sender] = balances[msg.sender].subtract(value);
            balances[to] = balances[to].add(value);
    
            // Adds the shareholder, if they don't already exist.
            shareholders.append(to);
    
            // Remove the shareholder if they no longer hold tokens.
            if (balances[msg.sender] == 0) {
                shareholders.remove(msg.sender);
            }
    
            emit Transfer(msg.sender, to, value);
            return true;
        }
    
        /**
         * @dev Transfer tokens from one address to another
         * @param from address The address which you want to send tokens from
         * @param to address The address which you want to transfer to
         * @param value uint256 the amount of tokens to be transferred
         *  The `transferFrom` function MUST NOT allow transfers to addresses that
         *  have not been verified and added to the contract.
         *  If the `to` address is not currently a shareholder then it MUST become one.
         *  If the transfer will reduce `from`'s balance to 0 then that address
         *  MUST be removed from the list of shareholders.
         */
        function transferFrom(address from, address to, uint256 value)
        public
        transferCheck(value, from)
        isNotCancelled(to)
        canTransferFrom(from, to)
        isUnlocked
        returns (bool) {
            if(msg.sender != owner) {
                require(value <= allowed[from][msg.sender], "Value exceeds what is allowed to transfer");
                allowed[from][msg.sender] = allowed[from][msg.sender].subtract(value);
            }
    
            balances[from] = balances[from].subtract(value);
            balances[to] = balances[to].add(value);
    
            // Adds the shareholder, if they don't already exist.
            shareholders.append(to);
    
            // Remove the shareholder if they no longer hold tokens.
            if (balances[msg.sender] == 0) {
                shareholders.remove(from);
            }
    
            emit Transfer(from, to, value);
            return true;
        }
    
        /**
         * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
         *
         * 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
         * @param spender The address which will spend the funds.
         * @param value The amount of tokens to be spent.
         */
        function approve(address spender, uint256 value)
        isUnlocked
        external
        returns (bool) {
            allowed[msg.sender][spender] = value;
            emit Approval(msg.sender, spender, value);
            return true;
        }
    
        function setIssuer(address newIssuer)
        isUnlocked
        onlyOwner
        external {
            issuer = newIssuer;
            emit IssuerSet(issuer, newIssuer);
        }
    
        /**
         * Tokens will be issued only to the issuer's address
         * @param quantity The amount of tokens to mint.
         * @return A boolean that indicates if the operation was successful.
         */
        function issueTokens(uint256 quantity)
        isUnlocked
        onlyIssuer
        canIssue
        public
        returns (bool) {
            address issuer = msg.sender;
            totalSupplyTokens = totalSupplyTokens.add(quantity);
            balances[issuer] = balances[issuer].add(quantity);
            shareholders.append(issuer);
            emit Issue(issuer, quantity);
            return true;
        }
    
        function finishIssuing()
        isUnlocked
        onlyIssuer
        canIssue
        public
        returns (bool) {
            issuingFinished = true;
            emit IssueFinished();
            return issuingFinished;
        }
    
        /**
         *  Cancel the original address and reissue the Tokens to the replacement address.
         *
         *  ***It's on the issuer to make sure the replacement address belongs to a verified investor.***
         *
         *  Access to this function MUST be strictly controlled.
         *  The `original` address MUST be removed from the set of verified addresses.
         *  Throw if the `original` address supplied is not a shareholder.
         *  Throw if the replacement address is not a verified address.
         *  This function MUST emit the `VerifiedAddressSuperseded` event.
         *  @param original The address to be superseded. This address MUST NOT be reused.
         *  @param replacement The address  that supersedes the original. This address MUST be verified.
         */
        function cancelAndReissue(address original, address replacement)
        isUnlocked
        onlyOwner
        isNotCancelled(replacement)
        external {
            // replace the original address in the shareholders mapping
            // and update all the associated mappings
            require(shareholders.exists(original) && !shareholders.exists(replacement), "Original doesn't exist or replacement does");
            shareholders.remove(original);
            shareholders.append(replacement);
            cancellations[original] = replacement;
            balances[replacement] = balances[original];
            balances[original] = 0;
            emit VerifiedAddressSuperseded(original, replacement, msg.sender);
        }
    
    }
    

    相关文章

      网友评论

          本文标题:首个STO项目 - tZERO源码分享

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