/// <summary>
        /// Claims unsold tokens
        /// </summary>
        /// <returns></returns>
        public static bool ClaimUnsoldTokens()
        {
            bool UnsoldTokensClaimed = Storage.Get(Storage.CurrentContext, StorageKeys.UnsoldTokensClaimed()).AsString() == "1";

            //This method can only be executed by the admin account, after the public sale, and can only be called once (use UnsoldTokensClaimed() storage item)
            if (Helpers.GetBlockTimestamp() >= ICOTemplate.PublicSaleEndTime() && UnsoldTokensClaimed == false && Helpers.VerifyIsAdminAccount())
            {
                byte[] address = ICOTemplate.AdditionalCompanyTokenFund;

                //Get amount remaining
                BigInteger amountRemaining = NEP5.CrowdsaleAvailableAmount();

                //Add vested amount to account
                TokenSale.SetVestingPeriodForAddress(address, "company", amountRemaining);

                //Set total supply
                Helpers.SetTotalSupply(amountRemaining);

                //Set the UnsoldTokensClaimed() storage item so ClaimUnsoldTokens() cannot be called again
                Storage.Put(Storage.CurrentContext, StorageKeys.UnsoldTokensClaimed(), "1");

                transfer(null, address, amountRemaining);

                Runtime.Notify("ClaimUnsoldTokens() tokens allocated", address, amountRemaining);

                return(true);
            }

            return(false);
        }
Beispiel #2
0
        /// <summary>
        /// return the amount of tokens that are subject to vesting period
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public static BigInteger SubjectToVestingPeriod(byte[] address)
        {
            BigInteger amountSubjectToVesting = 0;

            if (address.Length != 20)
            {
                return(amountSubjectToVesting);
            }

            object[] tokensVesting    = PublicTokensLocked(address);
            uint     currentTimestamp = Helpers.GetBlockTimestamp();

            if (tokensVesting.Length > 0)
            {
                // this account has some kind of vesting period
                for (int i = 0; i < tokensVesting.Length; i++)
                {
                    int        j             = i + 1;
                    uint       releaseDate   = (uint)tokensVesting[i];
                    BigInteger releaseAmount = (BigInteger)tokensVesting[j];

                    if (currentTimestamp < releaseDate)
                    {
                        // the release date has not yet occurred. add the releaseAmount to the balance
                        amountSubjectToVesting += releaseAmount;
                    }
                    i++;
                }
            }

            return(amountSubjectToVesting);
        }
        /// <summary>
        /// mint tokens is called when a user wishes to purchase tokens
        /// </summary>
        /// <returns></returns>
        public static bool MintTokens()
        {
            object[]    transactionData = Helpers.GetTransactionAndSaleData();
            Transaction tx = (Transaction)transactionData[0];

            byte[]     sender                    = (byte[])transactionData[1];
            byte[]     receiver                  = (byte[])transactionData[2];
            ulong      receivedNEO               = (ulong)transactionData[3];
            ulong      receivedGAS               = (ulong)transactionData[4];
            BigInteger whiteListGroupNumber      = (BigInteger)transactionData[5];
            BigInteger crowdsaleAvailableAmount  = (BigInteger)transactionData[6];
            BigInteger groupMaximumContribution  = (BigInteger)transactionData[7];
            BigInteger totalTokensPurchased      = (BigInteger)transactionData[8];
            BigInteger neoRemainingAfterPurchase = (BigInteger)transactionData[9];
            BigInteger gasRemainingAfterPurchase = (BigInteger)transactionData[10];
            BigInteger totalContributionBalance  = (BigInteger)transactionData[11];

            if (Helpers.GetBlockTimestamp() >= ICOTemplate.PublicSaleEndTime())
            {
                Runtime.Notify("MintTokens() failed. Token Sale is closed.", false);
                return(false);
            }

            if (!CanUserParticipateInSale(transactionData))
            {
                Runtime.Notify("MintTokens() CanUserParticipate failed", false);
                return(false);
            }

            byte[] lastTransactionHash = Storage.Get(Storage.CurrentContext, StorageKeys.MintTokensLastTX());
            if (lastTransactionHash == tx.Hash)
            {
                // ensure that minTokens doesnt process the same transaction more than once
                Runtime.Notify("MintTokens() not processing duplicate tx.Hash", tx.Hash);
                return(false);
            }

            Storage.Put(Storage.CurrentContext, StorageKeys.MintTokensLastTX(), tx.Hash);
            Runtime.Notify("MintTokens() receivedNEO / receivedGAS", receivedNEO, receivedGAS);

            if (neoRemainingAfterPurchase > 0 || gasRemainingAfterPurchase > 0)
            {
                // this purchase would have exceed the allowed max supply so we spent what we could and will refund the remainder
                refund(sender, neoRemainingAfterPurchase, gasRemainingAfterPurchase);
            }

            BigInteger senderAmountSubjectToVesting = SubjectToVestingPeriod(sender);
            BigInteger newTokenBalance = NEP5.BalanceOf(sender) + totalTokensPurchased + senderAmountSubjectToVesting;

            Helpers.SetBalanceOf(sender, newTokenBalance);
            Helpers.SetBalanceOfSaleContribution(sender, totalContributionBalance);
            Helpers.SetTotalSupply(totalTokensPurchased);

            transfer(null, sender, totalTokensPurchased);
            return(true);
        }
Beispiel #4
0
        /// <summary>
        /// allow an administrator to request the unlocking of founder tokens
        /// </summary>
        /// <param name="address">founders script hash</param>
        /// <param name="roundNumber">1-7</param>
        /// <returns></returns>
        public static bool UnlockFoundersTokens(byte[] address, int roundNumber)
        {
            if (address.Length != 20)
            {
                Runtime.Log("UnlockFoundersTokens() invalid address supplied");
                return(false);
            }

            byte[]     roundKey       = address.Concat(((BigInteger)roundNumber).AsByteArray());
            StorageMap unlockedRounds = Storage.CurrentContext.CreateMap(StorageKeys.FounderTokenUnlockRound());

            bool roundPreviouslyUnlocked = unlockedRounds.Get(roundKey).AsBigInteger() > 0;

            if (roundPreviouslyUnlocked)
            {
                Runtime.Log("UnlockFoundersTokens() round already unlocked");
                return(false);
            }

            object[] foundersVestingPeriod = GetCoreTeamVestingSchedule();

            uint currentTimestamp = Helpers.GetBlockTimestamp();
            int  roundIndex       = (roundNumber * 2) - 2;
            int  roundValueIndex  = roundIndex + 1;

            if (roundIndex < 0)
            {
                Runtime.Log("UnlockFoundersTokens() invalid round index (<0)");
                return(false);
            }

            uint       roundReleaseDate   = (uint)foundersVestingPeriod[roundIndex];
            BigInteger roundReleaseAmount = (BigInteger)foundersVestingPeriod[roundValueIndex];

            if (currentTimestamp < roundReleaseDate)
            {
                Runtime.Log("UnlockFoundersTokens() not scheduled for release");
                return(false);
            }


            object[] founderKeys = ICOContract.MoonlightFounderKeys();
            for (int i = 0; i < founderKeys.Length; i++)
            {
                byte[] founderKey = (byte[])founderKeys[i];
                if (founderKey == address)
                {
                    Runtime.Notify("UnlockFoundersTokens() releasing funds. currentTimestamp / roundReleaseDate / roundReleaseAmount", currentTimestamp, roundReleaseDate, roundReleaseAmount);
                    Helpers.SetBalanceOf(founderKey, NEP5.BalanceOf(founderKey) + roundReleaseAmount);            // set new balance for destination account
                    unlockedRounds.Put(roundKey, "1");
                    return(true);
                }
            }
            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// determine if groupNumber is eligible to participate in public sale yet
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <returns></returns>
        public static bool GroupParticipationIsUnlocked(int groupNumber)
        {
            if (groupNumber <= 0)
            {
                return(false);
            }

            uint unlockBlockTime = GetGroupUnlockTime(groupNumber);

            return(unlockBlockTime > 0 && unlockBlockTime <= Helpers.GetBlockTimestamp());
        }
        /// <summary>
        /// MintTokensEth is called when a the ETH contribution listener server triggers an Ether receive event
        /// </summary>
        /// <returns></returns>
        public static bool MintTokensEth(string ethAddress, byte[] neoAddress, ulong ethReceived)
        {
            object[]    transactionData = Helpers.GetEthTransactionAndSaleData(ethReceived, ethAddress, neoAddress);
            Transaction tx = (Transaction)transactionData[0];

            byte[]     sender                   = (byte[])transactionData[1];
            byte[]     receiver                 = (byte[])transactionData[2];
            BigInteger whiteListGroupNumber     = (BigInteger)transactionData[5];
            BigInteger crowdsaleAvailableAmount = (BigInteger)transactionData[6];
            BigInteger groupMaximumContribution = (BigInteger)transactionData[7];
            BigInteger totalTokensPurchased     = (BigInteger)transactionData[8] * NEP5.factor;
            BigInteger totalContributionBalance = (BigInteger)transactionData[9];

            if (!CanETHUserParticipateInSale(transactionData))
            {
                refundEth(ethAddress, ethReceived);
                Runtime.Notify("MintTokensEth() CanUserParticipate failed", false);
                return(false);
            }

            if (Helpers.GetBlockTimestamp() >= ICOTemplate.PublicSaleEndTime())
            {
                refundEth(ethAddress, ethReceived);
                Runtime.Notify("MintTokensEth() failed. Token Sale is closed.", false);
                return(false);
            }

            byte[] lastTransactionHash = Storage.Get(Storage.CurrentContext, StorageKeys.MintTokensEthLastTX());
            if (lastTransactionHash == tx.Hash)
            {
                // ensure that minTokens doesnt process the same transaction more than once
                Runtime.Notify("MintTokensEth() not processing duplicate tx.Hash", tx.Hash);
                return(false);
            }

            BigInteger tokenTotalSupply = NEP5.TotalSupply();

            Storage.Put(Storage.CurrentContext, StorageKeys.MintTokensEthLastTX(), tx.Hash);
            Runtime.Notify("MintTokensEth() receivedETH", ethReceived);

            BigInteger senderAmountSubjectToVesting = TokenSale.SubjectToVestingPeriod(sender);
            BigInteger newTokenBalance = NEP5.BalanceOf(sender) + totalTokensPurchased + senderAmountSubjectToVesting;

            Helpers.SetBalanceOf(sender, newTokenBalance);
            Helpers.SetBalanceOfSaleContribution(sender, totalContributionBalance);
            Helpers.SetTotalSupply(totalTokensPurchased);

            transfer(null, sender, totalTokensPurchased);
            return(true);
        }
Beispiel #7
0
        /// <summary>
        /// initialise the smart contract for use
        /// </summary>
        /// <returns></returns>
        public static bool InitSmartContract()
        {
            if (Helpers.ContractInitialised())
            {
                // contract can only be initialised once
                Runtime.Log("InitSmartContract() contract already initialised");
                return(false);
            }

            uint ContractInitTime = Helpers.GetBlockTimestamp();

            Storage.Put(Storage.CurrentContext, StorageKeys.ContractInitTime(), ContractInitTime);

            // assign pre-allocated tokens to the project
            object[] immediateAllocation = ICOContract.ImmediateProjectGrowthAllocation();
            object[] vestedAllocation    = ICOContract.VestedProjectGrowthAllocation();

            BigInteger immediateProjectAllocationValue = ((ICOContract.TokenMaxSupply * (BigInteger)immediateAllocation[0]) / 100) * NEP5.factor;
            BigInteger vestedProjectAllocationValue    = ((ICOContract.TokenMaxSupply * (BigInteger)vestedAllocation[0]) / 100) * NEP5.factor;

            Helpers.SetBalanceOf(ICOContract.MoonlightProjectKey(), immediateProjectAllocationValue + vestedProjectAllocationValue);
            Helpers.SetBalanceOfVestedAmount(ICOContract.MoonlightProjectKey(), immediateProjectAllocationValue + vestedProjectAllocationValue);

            // lockup a portion of the tokens to be released in the future
            uint vestedGrowthReleaseDate = (uint)vestedAllocation[1] + ContractInitTime;

            object[]   vestedTokenPeriod = new object[] { vestedGrowthReleaseDate, vestedProjectAllocationValue };
            StorageMap vestingData       = Storage.CurrentContext.CreateMap(StorageKeys.VestedTokenPrefix());

            vestingData.Put(ICOContract.MoonlightProjectKey(), vestedTokenPeriod.Serialize());

            // token allocation to MoonlightFounderKeys - update the total supply to include balance - these funds will be unlocked gradually
            BigInteger founderTokenAllocation = ((ICOContract.TokenMaxSupply * (BigInteger)ICOContract.MoonlightFoundersAllocationPercentage()) / 100) * NEP5.factor;

            // token allocated to presale
            BigInteger presaleAllocationMaxValue = ((ICOContract.TokenMaxSupply * (BigInteger)ICOContract.PresaleAllocationPercentage()) / 100) * NEP5.factor;

            // update the total supply to reflect the project allocated tokens
            BigInteger totalSupply = immediateProjectAllocationValue + vestedProjectAllocationValue + founderTokenAllocation + presaleAllocationMaxValue;

            Helpers.SetTotalSupply(totalSupply);

            UpdateAdminAddress(ICOContract.InitialAdminAccount);
            EnableDEXWhitelisting(ICOContract.WhitelistDEXListings());
            Runtime.Log("InitSmartContract() contract initialisation complete");
            return(true);
        }
Beispiel #8
0
        /// <summary>
        /// get the maximum number of NOS that can be purchased by groupNumber during the public sale
        /// </summary>
        /// <param name="groupNumber"></param>
        /// <returns></returns>
        public static BigInteger GetGroupMaxContribution(BigInteger groupNumber)
        {
            BigInteger maxContribution           = 0;
            uint       latestTimeStamp           = Helpers.GetBlockTimestamp();
            uint       publicSaleMaxContribution = (uint)ICOTemplate.MaximumContributionAmount();
            uint       publicSaleEndTime         = (uint)ICOTemplate.PublicSaleEndTime();

            //If latest block timestamp is larger than presale start and smaller than presale end: check presale tier contributions.
            if (latestTimeStamp >= (uint)ICOTemplate.PresaleStartTime() && latestTimeStamp <= (uint)ICOTemplate.PresaleEndTime())
            {
                //Presale has not ended. Only presale can participate.
                if (groupNumber == 1)
                {
                    //Pre-sale tier 1.
                    maxContribution = (uint)ICOTemplate.PresaleTierOne();
                }
                else if (groupNumber == 2)
                {
                    //Pre-sale tier 2.
                    maxContribution = (uint)ICOTemplate.PresaleTierTwo();
                }
                else if (groupNumber == 3)
                {
                    //Pre-sale tier 3.
                    maxContribution = (uint)ICOTemplate.PresaleTierThree();
                }
                else if (groupNumber == 4)
                {
                    //Tier 4
                    maxContribution = (uint)ICOTemplate.PresaleTierFour();
                }
            }
            //Otherwise we're in the public sale; get the publicSaleMaxContribution
            //publicSaleMaxContribution returns the max contribution based on the presale phase using Helpers.GetPublicSaleMaxContribution()
            else if (groupNumber > 0 && groupNumber <= 4 && latestTimeStamp >= (uint)ICOTemplate.PublicSaleStartTime() && latestTimeStamp <= publicSaleEndTime)
            {
                maxContribution = publicSaleMaxContribution;
            }

            return(maxContribution);
        }
        /// <summary>
        /// initialise the smart contract for use
        /// </summary>
        /// <returns></returns>
        public static bool InitSmartContract()
        {
            if (Helpers.ContractInitialised())
            {
                // contract can only be initialised once
                Runtime.Log("InitSmartContract() contract already initialised");
                return(false);
            }


            uint ContractInitTime = Helpers.GetBlockTimestamp();

            Storage.Put(Storage.CurrentContext, StorageKeys.ContractInitTime(), ContractInitTime);

            // assign pre-allocated tokens to the NosProjectKey() (10,000,000 tokens)
            BigInteger immediateProjectAllocationValue = ICOTemplate.ImmediateCompanyReserve() * NEP5.factor;


            Helpers.SetBalanceOf(ICOTemplate.NosProjectKey, immediateProjectAllocationValue);
            transfer(null, ICOTemplate.NosProjectKey, immediateProjectAllocationValue);

            // token allocated to private sale & vested reserves & incentives
            BigInteger presaleAllocationMaxValue = ICOTemplate.LockedTokenAllocationAmount() * NEP5.factor;

            // update the total supply to reflect the project allocated tokens
            BigInteger totalSupply = immediateProjectAllocationValue + presaleAllocationMaxValue;

            Helpers.SetTotalSupply(totalSupply);

            UpdateAdminAddress(ICOTemplate.InitialAdminAccount);

            EnableTransferFromWhitelisting(ICOTemplate.WhitelistTransferFromListings());

            Runtime.Log("InitSmartContract() contract initialisation complete");
            return(true);
        }
Beispiel #10
0
 /// <summary>
 /// once initial presale allocation completed perform lock that prevents allocation being used
 /// </summary>
 /// <returns></returns>
 public static bool LockPresaleAllocation()
 {
     Runtime.Log("LockPresaleAllocation() further presale allocations locked");
     Storage.Put(Storage.CurrentContext, StorageKeys.PresaleAllocationLocked(), Helpers.GetBlockTimestamp());
     return(true);
 }
        /// <summary>
        /// set a vesting schedule, as defined in the whitepaper, for tokens purchased during the presale
        /// </summary>
        /// <param name="address"></param>
        /// <param name="tokenBalance"></param>
        /// <returns></returns>
        public static bool SetVestingPeriodForAddress(byte[] address, string allocationType, BigInteger tokensPurchased)
        {
            if (allocationType != "incentive" && allocationType != "privateSale" && allocationType != "company")
            {
                return(false);
            }

            if (address.Length != 20)
            {
                return(false);
            }

            BigInteger currentAvailableBalance = 0;        // how many tokens will be immediately available to the owner

            uint       contractInitTime   = Helpers.GetContractInitTime();
            uint       currentTimestamp   = Helpers.GetBlockTimestamp();
            StorageMap vestingData        = Storage.CurrentContext.CreateMap(StorageKeys.VestedTokenPrefix());
            uint       initialReleaseDate = 0;
            uint       releaseFrequency   = 0;

            object[] vestingObj = new object[0];

            if (allocationType == "incentive")
            {
                vestingObj         = ICOTemplate.VestingIncentive();
                initialReleaseDate = (uint)vestingObj[0] + contractInitTime;
                releaseFrequency   = (uint)vestingObj[1];
            }
            else if (allocationType == "privateSale")
            {
                vestingObj         = ICOTemplate.VestingPrivateSale();
                initialReleaseDate = contractInitTime;
                releaseFrequency   = (uint)vestingObj[0];
            }
            else if (allocationType == "company")
            {
                vestingObj         = ICOTemplate.VestingCompany();
                initialReleaseDate = (uint)vestingObj[0] + contractInitTime;
                releaseFrequency   = (uint)vestingObj[0];
            }

            object[] releasePeriod = new object[4];

            releasePeriod[0] = initialReleaseDate;
            releasePeriod[1] = initialReleaseDate + releaseFrequency;
            releasePeriod[2] = initialReleaseDate + (releaseFrequency * 2);
            releasePeriod[3] = initialReleaseDate + (releaseFrequency * 3);

            // calculate how much should be released
            BigInteger releaseAmount = tokensPurchased * ICOTemplate.DistributionPercentage() / 100;

            object[] lockoutTimes = new object[] { releasePeriod[0], releaseAmount, releasePeriod[1], releaseAmount, releasePeriod[2], releaseAmount, releasePeriod[3], releaseAmount };
            vestingData.Put(address, lockoutTimes.Serialize());

            // ensure the total amount purchased is saved
            Helpers.SetBalanceOf(address, tokensPurchased);
            Helpers.SetBalanceOfVestedAmount(address, tokensPurchased, allocationType);
            transfer(null, address, tokensPurchased);

            return(true);
        }
Beispiel #12
0
        /// <summary>
        /// transfer an amount from the "from" account to the "to" acount if the originator has been approved to transfer the requested amount.
        /// </summary>
        /// <param name="originator"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="amount"></param>
        /// <param name="caller"></param>
        /// <param name="entry"></param>
        /// <returns></returns>
        public static bool TransferFrom(byte[] originator, byte[] from, byte[] to, BigInteger amount, byte[] caller, byte[] entry)
        {
            if (Helpers.GetBlockTimestamp() < ICOTemplate.PublicSaleEndTime())
            {
                Runtime.Log("TransferFrom() not available before ICOTemplate.PublicSaleEndTime()");
                return(false);
            }

            if (caller != entry && !Helpers.IsContractWhitelistedTransferFrom(caller))
            {
                originator = caller;
            }

            if (originator.Length != 20 || from.Length != 20 || to.Length != 20)
            {
                Runtime.Log("TransferFrom() (originator|from|to).Length != 20");
                return(false);
            }

            if (amount < 0)
            {
                Runtime.Log("TransferFrom() invalid transfer amount must be >= 0");
                throw new Exception();
            }

            BigInteger approvedTransferAmount = Allowance(from, to);    // how many tokens is this address authorised to transfer
            BigInteger fromBalance            = BalanceOf(from);        // retrieve balance of authorised account

            if (approvedTransferAmount < amount || fromBalance < amount)
            {
                // don't transfer if funds not available
                Runtime.Notify("TransferFrom() (authorisedAmount|fromBalance) < transferValue", approvedTransferAmount, fromBalance, amount);
                return(false);
            }

            if (amount == 0 || from == to)
            {
                // don't accept a meaningless value
                Runtime.Log("TransferFrom() empty transfer amount or from==to");
                transfer(from, to, amount);
                return(true);    // as per nep5 standard - return true when amount is 0 or from == to
            }

            if (!Runtime.CheckWitness(originator))
            {
                // ensure transaction is signed properly by the request originator
                Runtime.Log("TransferFrom() CheckWitness failed");
                return(false);
            }

            BigInteger recipientBalance = BalanceOf(to);
            BigInteger recipientAmountSubjectToVesting = TokenSale.SubjectToVestingPeriod(to);
            BigInteger senderAmountSubjectToVesting    = TokenSale.SubjectToVestingPeriod(from);

            BigInteger newBalance = fromBalance - amount;

            Helpers.SetBalanceOf(from, newBalance + senderAmountSubjectToVesting);                  // remove balance from originating account
            Helpers.SetBalanceOf(to, recipientBalance + recipientAmountSubjectToVesting + amount);  // set new balance for destination account
            Helpers.SetAllowanceAmount(from.Concat(originator), approvedTransferAmount - amount);   // deduct transferred amount from allowance

            transfer(from, to, amount);
            return(true);
        }
Beispiel #13
0
        /// <summary>
        /// NEP5: Transfer tokens from one account to another
        /// </summary>
        /// <param name="from">sender address</param>
        /// <param name="to">recipient address</param>
        /// <param name="amount">number of tokens to transfer</param>
        /// <param name="caller"></param>
        /// <param name="entry"></param>
        /// <returns></returns>
        public static bool Transfer(byte[] from, byte[] to, BigInteger amount, byte[] caller, byte[] entry)
        {
            if (Helpers.GetBlockTimestamp() < ICOTemplate.PublicSaleEndTime())
            {
                Runtime.Log("Transfer() not available before ICOTemplate.PublicSaleEndTime()");
                return(false);
            }

            if (caller != entry && !Helpers.IsContractWhitelistedTransferFrom(caller))
            {
                from = caller;
            }

            if (from.Length != 20 || to.Length != 20)
            {
                Runtime.Log("Transfer() (from|to).Length != 20");
                return(false);
            }

            if (amount < 0)
            {
                Runtime.Log("Transfer() invalid transfer amount must be >= 0");
                throw new Exception();
            }

            BigInteger fromBalance = BalanceOf(from);                   // retrieve balance of originating account

            if (fromBalance < amount)
            {
                Runtime.Log("Transfer() fromBalance < transferValue");
                // don't transfer if funds not available
                return(false);
            }

            if (amount == 0 || from == to)
            {
                // don't accept a meaningless value
                Runtime.Log("Transfer() empty transfer amount or from==to");
                transfer(from, to, amount);
                return(true);    // as per nep5 standard - return true when amount is 0 or from == to
            }

            if (!Runtime.CheckWitness(from))
            {
                // ensure transaction is signed properly by the owner of the tokens
                Runtime.Log("Transfer() CheckWitness failed");
                return(false);
            }

            BigInteger recipientBalance = BalanceOf(to);
            BigInteger recipientAmountSubjectToVesting = TokenSale.SubjectToVestingPeriod(to);
            BigInteger senderAmountSubjectToVesting    = TokenSale.SubjectToVestingPeriod(from);

            BigInteger newBalance = fromBalance - amount;

            Helpers.SetBalanceOf(from, newBalance + senderAmountSubjectToVesting);                  // remove balance from originating account
            Helpers.SetBalanceOf(to, recipientBalance + recipientAmountSubjectToVesting + amount);  // set new balance for destination account

            transfer(from, to, amount);
            return(true);
        }