Ejemplo n.º 1
0
    def exchange(self, token: Token):
        """
        Make a token sale contribution to exchange NEO for NRVE
        :param token: Token The token object with NEP5/sale settings
        :return:
            bool: Whether the exchange was successful
        """

        attachments = get_asset_attachments()  # type:  Attachments

        storage = StorageAPI()

        # this looks up whether the exchange can proceed
        tokens = self.check_and_calculate_tokens(token, attachments, storage,
                                                 False)

        if tokens <= 0:
            print("Cannot exchange value")
            # This should only happen in the case that there are a lot of TX on the final
            # block before the total amount is reached.  An amount of TX will get through
            # the verification phase because the total amount cannot be updated during that phase
            # because of this, there should be a process in place to manually refund tokens
            if attachments.neo_attached > 0:
                OnRefund(attachments.sender_addr, attachments.neo_attached)
            return False

        self.mint_tokens(token, attachments.receiver_addr,
                         attachments.sender_addr, tokens, storage)

        # update the total sold during the public sale
        public_sale_sold = storage.get(token.public_sale_sold_key)

        public_sale_sold += tokens

        storage.put(token.public_sale_sold_key, public_sale_sold)

        # track contributions as a separate event for token sale account page transaction updates
        OnContribution(attachments.sender_addr, attachments.neo_attached,
                       tokens)

        return True
Ejemplo n.º 2
0
    def mint_rewards_tokens(self, token: Token, args):
        """
        Mint tokens for the rewards pool
        :param token: the token being minted for the rewards pool
        :param args: the address and number of tokens to mint
        :return: True if successful
        """
        storage = StorageAPI()

        owner = storage.get(token.owner_key)
        if not CheckWitness(owner):
            return False

        if len(args) != 2:
            return False

        address = args[0]
        tokens = args[1]

        if len(address) != 20:
            return False
        if tokens <= 0:
            return False

        now = get_now()

        # no minting rewards tokens until after the token sale ends
        if now < self.sale_end:
            print("can't mint_rewards_tokens before sale ends")
            return False

        rewards_fund_tokens_distributed = storage.get(
            self.rewards_fund_token_distribution_key)

        rewards_fund_tokens_distributed += tokens

        # don't allow more than the max tokens to be distributed
        if rewards_fund_tokens_distributed > self.rewards_fund_tokens_max:
            print("can't exceed mint_rewards_tokens limit")
            return False

        storage.put(self.rewards_fund_token_distribution_key,
                    rewards_fund_tokens_distributed)

        attachments = get_asset_attachments()  # type:  Attachments

        #self.mint_tokens(token, attachments.receiver_addr, address, tokens, storage)
        from_address = attachments.receiver_addr
        to_address = address

        # bl: the following is an exact copy of the mint_tokens function. invoking self.mint_tokens will break the
        # execution of this method due to a neo-boa compiler issue. this results in a lot of code duplication,
        # but it's preferable to the alternative of a broken smart contract. refer: https://github.com/CityOfZion/neo-boa/issues/40

        # lookup the current balance of the address
        current_balance = storage.get(to_address)

        # add it to the exchanged tokens and persist in storage
        new_total = tokens + current_balance
        storage.put(to_address, new_total)

        # update the in circulation amount
        token.add_to_circulation(tokens, storage)

        # dispatch transfer event
        OnTransfer(from_address, to_address, tokens)

        return True
Ejemplo n.º 3
0
    def transfer_company_tokens(self, token: Token, args):
        """
        Transfer company tokens to a wallet address according to the 2-year company token vesting schedule
        :param token: the token being minted for the company
        :param args: the address and number of tokens to mint
        :return: True if successful
        """
        storage = StorageAPI()

        owner = storage.get(token.owner_key)
        if not CheckWitness(owner):
            return False

        if len(args) != 2:
            return False

        address = args[0]
        tokens = args[1]

        if len(address) != 20:
            return False
        if tokens <= 0:
            return False

        now = get_now()

        seconds_in_year = 31536000

        # no company token distribution until after the ICO ends
        if now < self.sale_end:
            print("can't transfer_company_tokens before sale ends")
            return False

        # in the first year, allow 50% token distribution
        if now < (self.sale_end + seconds_in_year):
            max_token_distribution = self.company_tokens_max * 5 / 10
        # in the second year, allow 75% total token distribution
        elif now < (self.sale_end + (2 * seconds_in_year)):
            max_token_distribution = self.company_tokens_max * 75 / 100
        # beyond the second year, allow 100% total token distribution
        else:
            max_token_distribution = self.company_tokens_max

        company_tokens_distributed = storage.get(
            self.company_token_distribution_key)

        company_tokens_distributed += tokens

        # don't allow more than the max tokens to be distributed
        if company_tokens_distributed > max_token_distribution:
            print("can't exceed transfer_company_tokens vesting limit")
            return False

        storage.put(self.company_token_distribution_key,
                    company_tokens_distributed)

        attachments = get_asset_attachments()  # type:  Attachments

        #self.mint_tokens(token, attachments.receiver_addr, address, tokens, storage)
        from_address = attachments.receiver_addr
        to_address = address

        # bl: the following is an exact copy of the mint_tokens function. invoking self.mint_tokens will break the
        # execution of this method due to a neo-boa compiler issue. this results in a lot of code duplication,
        # but it's preferable to the alternative of a broken smart contract. refer: https://github.com/CityOfZion/neo-boa/issues/40

        # lookup the current balance of the address
        current_balance = storage.get(to_address)

        # add it to the exchanged tokens and persist in storage
        new_total = tokens + current_balance
        storage.put(to_address, new_total)

        # update the in circulation amount
        token.add_to_circulation(tokens, storage)

        # dispatch transfer event
        OnTransfer(from_address, to_address, tokens)

        return True
Ejemplo n.º 4
0
    def transfer_presale_tokens(self, token: Token, args):
        """
        Transfer pre-sale tokens to a wallet address according to the 800 NEO minimum and 3,000 NEO maximum individual limits
        :param token: the token being minted for the team
        :param args: the address and number of neo for the contribution
        :return: True if successful
        """
        storage = StorageAPI()

        owner = storage.get(token.owner_key)
        if not CheckWitness(owner):
            return False

        if len(args) != 2:
            return False

        address = args[0]
        neo = args[1]

        if len(address) != 20:
            return False
        if neo <= 0:
            return False

        presale_minted = storage.get(token.presale_minted_key)

        max_neo_remaining = (self.presale_token_limit -
                             presale_minted) / self.presale_tokens_per_neo

        # calculate the number of tokens based on the neo value supplied
        tokens = neo * self.presale_tokens_per_neo

        new_presale_minted = presale_minted + tokens

        # don't allow more than the presale token limit to be distributed
        if new_presale_minted > self.presale_token_limit:
            print("transfer would exceed presale token limit")
            return False

        # protect against scenarios where we could deadlock the contract by making
        # a mistake in our manual distribution. allow amount smaller than 800 NEO
        # if we're down to fewer than 800 NEO remaining to close the pre-sale
        if neo < self.presale_minimum and self.presale_minimum < max_neo_remaining:
            print("insufficient presale contribution")
            return False

        # check if they have already exchanged in the limited round
        phase_key = concat(self.presale_phase_key, address)

        total_amount_contributed = storage.get(phase_key)

        # add on the amount of the new contribution
        total_amount_contributed += neo

        if total_amount_contributed > self.presale_individual_limit:
            print("transfer would exceed presale individual limit")
            return False

        storage.put(phase_key, total_amount_contributed)

        attachments = get_asset_attachments()  # type:  Attachments

        #self.mint_tokens(token, attachments.receiver_addr, address, tokens, storage)
        from_address = attachments.receiver_addr
        to_address = address

        # bl: the following is an exact copy of the mint_tokens function (except for the OnPreSaleMint). invoking self.mint_tokens will break the
        # execution of this method due to a neo-boa compiler issue. this results in a lot of code duplication,
        # but it's preferable to the alternative of a broken smart contract. refer: https://github.com/CityOfZion/neo-boa/issues/40

        # lookup the current balance of the address
        current_balance = storage.get(to_address)

        # add it to the exchanged tokens and persist in storage
        new_total = tokens + current_balance
        storage.put(to_address, new_total)

        # update the in circulation amount
        token.add_to_circulation(tokens, storage)

        # update the total pre-sale tokens that have been minted
        storage.put(token.presale_minted_key, new_presale_minted)

        # track pre-sale mint as a separate event for easier tracking
        OnPreSaleMint(to_address, neo, tokens)

        # dispatch transfer event
        OnTransfer(from_address, to_address, tokens)

        return True
def Main(operation, args):
    """

    :param operation: str The name of the operation to perform
    :param args: list A list of arguments along with the operation
    :return:
        bytearray: The result of the operation
    """

    trigger = GetTrigger()
    token = Token()

    # This is used in the Verification portion of the contract
    # To determine whether a transfer of system assets (NEO/Gas) involving
    # This contract's address can proceed
    if trigger == Verification:

        storage = StorageAPI()

        owner = storage.get(token.owner_key)

        if owner:
            # If the invoker is the owner of this contract, proceed
            if CheckWitness(owner):
                return True
        else:
            # check original_owner if not deployed yet (i.e. no owner in storage)
            if CheckWitness(token.original_owner):
                return True

        # Otherwise, we need to lookup the assets and determine
        # If attachments of assets is ok
        attachments = get_asset_attachments()  # type:Attachments

        crowdsale = Crowdsale()

        # the exchange will be allowed if the number of tokens to convert to is greater than zero.
        # zero indicates that there is a reason this contribution will not be allowed
        return crowdsale.check_and_calculate_tokens(token, attachments,
                                                    storage, True) > 0

    elif trigger == Application:

        if operation != None:

            nep = NEP5Handler()

            for op in nep.get_methods():
                if operation == op:
                    return nep.handle_nep51(operation, args, token)

            if operation == 'deploy':
                return deploy(token)

            if operation == 'circulation':
                storage = StorageAPI()
                return token.get_circulation(storage)

            sale = Crowdsale()

            if operation == 'mintTokens':
                return sale.exchange(token)

            if operation == 'crowdsale_register':
                return sale.kyc_register(args, token)

            if operation == 'crowdsale_deregister':
                return sale.kyc_deregister(args, token)

            if operation == 'crowdsale_status':
                return sale.kyc_status(args)

            if operation == 'crowdsale_available':
                return token.crowdsale_available_amount()

            if operation == 'transfer_presale_tokens':
                return sale.transfer_presale_tokens(token, args)

            if operation == 'transfer_team_tokens':
                return sale.transfer_team_tokens(token, args)

            if operation == 'transfer_company_tokens':
                return sale.transfer_company_tokens(token, args)

            if operation == 'mint_rewards_tokens':
                return sale.mint_rewards_tokens(token, args)

            if operation == 'change_owner':
                new_owner = args[0]
                return change_owner(token, new_owner)

            if operation == 'accept_owner':
                return accept_owner(token)

            if operation == 'cancel_change_owner':
                return cancel_change_owner(token)

            if operation == 'start_public_sale':
                return sale.start_public_sale(token)

            if operation == 'pause_sale':
                return pause_sale(token)

            if operation == 'resume_sale':
                return resume_sale(token)

            return 'unknown operation'

    return False