Example #1
0
        /// <summary>
        ///     Main purpose of this function is to get an array of transfer objects as input, and then prepare the transfer by
        ///     generating the correct bundle,
        ///     as well as choosing and signing the inputs if necessary (if it's a value transfer). The output of this function is
        ///     an array of the raw transaction data (trytes)
        /// </summary>
        /// <param name="seed">81-tryte encoded address of recipient</param>
        /// <param name="security"></param>
        /// <param name="transfers">the transfers to prepare</param>
        /// <param name="inputs">Optional (default null). The inputs</param>
        /// <param name="remainderAddress">
        ///     Optional (default null). if defined, this address will be used for sending the remainder
        ///     value (of the inputs) to.
        /// </param>
        /// <param name="validateInputs"></param>
        /// <returns>a list containing the trytes of the new bundle</returns>
        public List <string> PrepareTransfers(
            string seed, int security,
            Transfer[] transfers,
            string remainderAddress,
            List <Input> inputs,
            bool validateInputs)
        {
            // validate seed
            if (!InputValidator.IsValidSeed(seed))
            {
                throw new IllegalStateException("Invalid seed provided.");
            }


            if (security < 1)
            {
                throw new ArgumentException("Invalid security level provided.");
            }

            // Input validation of transfers object
            InputValidator.CheckTransferArray(transfers);

            // Create a new bundle
            var bundle             = new Bundle();
            var signatureFragments = new List <string>();

            long totalValue = 0;
            var  tag        = "";

            //
            //  Iterate over all transfers, get totalValue
            //  and prepare the signatureFragments, message and tag
            //
            foreach (var transfer in transfers)
            {
                // remove the checksum of the address if provided
                transfer.Address = transfer.Address.RemoveChecksum();

                var signatureMessageLength = 1;

                // If message longer than 2187 trytes, increase signatureMessageLength (add 2nd transaction)
                if (transfer.Message.Length > Constants.MessageLength)
                {
                    // Get total length, message / maxLength (2187 trytes)
                    signatureMessageLength += (int)Math.Floor((double)transfer.Message.Length / Constants.MessageLength);

                    var msgCopy = transfer.Message;

                    // While there is still a message, copy it
                    while (!string.IsNullOrEmpty(msgCopy))
                    {
                        var fragment = msgCopy.Substring(0, 2187 > msgCopy.Length ? msgCopy.Length : 2187);
                        msgCopy = msgCopy.Substring(2187, msgCopy.Length - 2187);

                        // Pad remainder of fragment
                        while (fragment.Length < 2187)
                        {
                            fragment += '9';
                        }

                        signatureFragments.Add(fragment);
                    }
                }
                else
                {
                    // Else, get single fragment with 2187 of 9's trytes
                    var fragment = string.Empty;

                    if (!string.IsNullOrEmpty(transfer.Message))
                    {
                        fragment = transfer.Message.Substring(0,
                                                              transfer.Message.Length < 2187 ? transfer.Message.Length : 2187);
                    }

                    while (fragment.Length < 2187)
                    {
                        fragment += '9';
                    }

                    signatureFragments.Add(fragment);
                }

                // get current timestamp in seconds
                var timestamp = (long)Math.Floor((double)IotaApiUtils.CreateTimeStampNow() / 1000);

                // If no tag defined, get 27 tryte tag.

                tag = string.IsNullOrEmpty(transfer.Tag) ? "999999999999999999999999999" : transfer.Tag;


                // Pad for required 27 tryte length
                while (tag.Length < 27)
                {
                    tag += '9';
                }


                // Add first entries to the bundle
                // Slice the address in case the user provided a checksummed one
                bundle.AddEntry(signatureMessageLength, transfer.Address, transfer.Value, tag, timestamp);
                // Sum up total value
                totalValue += transfer.Value;
            }

            // Get inputs if we are sending tokens
            if (totalValue != 0)
            {
                if (inputs != null && inputs.Count > 0)
                {
                    // Get list if addresses of the provided inputs
                    var inputAddresses = new List <string>();
                    foreach (var input in inputs)
                    {
                        inputAddresses.Add(input.Address);
                    }

                    var balances = GetBalances(inputAddresses, 100);

                    var confirmedInputs = new List <Input>();

                    long totalBalance = 0;
                    for (var i = 0; i < balances.Balances.Count; i++)
                    {
                        var thisBalance = balances.Balances[i];
                        totalBalance += thisBalance;

                        // If input has balance, add it to confirmedInputs
                        if (thisBalance > 0)
                        {
                            var inputEl = inputs[i];
                            inputEl.Balance = thisBalance;

                            confirmedInputs.Add(inputEl);
                        }
                    }

                    // Return not enough balance error
                    if (totalValue > totalBalance)
                    {
                        throw new NotEnoughBalanceException(totalValue);
                    }

                    return(AddRemainder(seed, security, confirmedInputs, bundle, tag, totalValue, remainderAddress,
                                        signatureFragments));
                }

                //  Case 2: Get inputs deterministically
                //
                //  If no inputs provided, derive the addresses from the seed and
                //  confirm that the inputs exceed the threshold
                else
                {
                    var inputList = GetInputs(seed, security, 0, 0, (int)totalValue).InputsList;
                    return(AddRemainder(seed, security, inputList, bundle, tag, totalValue, remainderAddress,
                                        signatureFragments));
                }
            }

            // If no input required, don't sign and simply finalize the bundle
            bundle.FinalizeBundle(_curl.Clone());
            bundle.AddTrytes(signatureFragments);

            var bundleTrytes = new List <string>();

            bundle.Transactions.ForEach(tx => bundleTrytes.Add(tx.ToTransactionTrytes()));

            bundleTrytes.Reverse();
            return(bundleTrytes);
        }
Example #2
0
        /// <summary>
        /// Main purpose of this function is to get an array of transfer objects as input, and then prepare the transfer by generating the correct bundle,
        /// as well as choosing and signing the inputs if necessary (if it's a value transfer). The output of this function is an array of the raw transaction data (trytes)
        /// </summary>
        /// <param name="seed">81-tryte encoded address of recipient</param>
        /// <param name="transfers">the transfers to prepare</param>
        /// <param name="inputs">Optional (default null). The inputs</param>
        /// <param name="remainderAddress">Optional (default null). if defined, this address will be used for sending the remainder value (of the inputs) to.</param>
        /// <returns>a list containing the trytes of the new bundle</returns>
        public List <string> PrepareTransfers(string seed, Transfer[] transfers, List <Input> inputs = null,
                                              string remainderAddress = null)
        {
            InputValidator.CheckTransferArray(transfers);

            // Create a new bundle
            Bundle        bundle             = new Bundle();
            List <string> signatureFragments = new List <string>();
            long          totalValue         = 0;
            string        tag = "";

            //
            //  Iterate over all transfers, get totalValue
            //  and prepare the signatureFragments, message and tag
            //
            for (int i = 0; i < transfers.Length; i++)
            {
                int signatureMessageLength = 1;

                // If message longer than 2187 trytes, increase signatureMessageLength (add 2nd transaction)
                if (transfers[i].Message.Length > 2187)
                {
                    // Get total length, message / maxLength (2187 trytes)
                    signatureMessageLength += (int)Math.Floor(((double)transfers[i].Message.Length / 2187));

                    var msgCopy = transfers[i].Message;

                    // While there is still a message, copy it
                    while (msgCopy != null)
                    {
                        var fragment = msgCopy.Substring(0, 2187 > msgCopy.Length ? msgCopy.Length : 2187);
                        msgCopy = msgCopy.Substring(2187, msgCopy.Length - 2187);

                        // Pad remainder of fragment
                        for (var j = 0; fragment.Length < 2187; j++)
                        {
                            fragment += '9';
                        }

                        signatureFragments.Add(fragment);
                    }
                }
                else
                {
                    // Else, get single fragment with 2187 of 9's trytes
                    string fragment = "";

                    if (transfers[i].Message != null)
                    {
                        fragment = transfers[i].Message.Substring(0,
                                                                  transfers[i].Message.Length < 2187 ? transfers[i].Message.Length : 2187);
                    }

                    for (var j = 0; fragment.Length < 2187; j++)
                    {
                        fragment += '9';
                    }

                    signatureFragments.Add(fragment);
                }

                // get current timestamp in seconds
                long timestamp = IotaApiUtils.CreateTimeStampNow();

                // If no tag defined, get 27 tryte tag.
                tag = transfers[i].Tag != null ? transfers[i].Tag : "999999999999999999999999999";

                // Pad for required 27 tryte length
                for (var j = 0; tag.Length < 27; j++)
                {
                    tag += '9';
                }

                // Add first entries to the bundle
                // Slice the address in case the user provided a checksummed one
                bundle.AddEntry(signatureMessageLength, transfers[i].Address, transfers[i].Value, tag, timestamp);
                // Sum up total value
                totalValue += transfers[i].Value;
            }

            // Get inputs if we are sending tokens
            if (totalValue != 0)
            {
                //  Case 1: user provided inputs
                //
                //  Validate the inputs by calling getBalances
                if (inputs != null && inputs.Count > 0)
                {
                    // Get list if addresses of the provided inputs
                    List <string> inputAddresses = new List <string>();
                    foreach (var input in inputs)
                    {
                        inputAddresses.Add(input.Address);
                    }

                    GetBalancesResponse balances = GetBalances(inputAddresses, 100);

                    List <Input> confirmedInputs = new List <Input>();

                    long totalBalance = 0;
                    for (var i = 0; i < balances.Balances.Count; i++)
                    {
                        var thisBalance = balances.Balances[i];
                        totalBalance += thisBalance;

                        // If input has balance, add it to confirmedInputs
                        if (thisBalance > 0)
                        {
                            var inputEl = inputs[i];
                            inputEl.Balance = thisBalance;

                            confirmedInputs.Add(inputEl);
                        }
                    }

                    // Return not enough balance error
                    if (totalValue > totalBalance)
                    {
                        throw new NotEnoughBalanceException(totalValue);
                    }

                    return(AddRemainder(seed, confirmedInputs, bundle, tag, totalValue, remainderAddress,
                                        signatureFragments));
                }

                //  Case 2: Get inputs deterministically
                //
                //  If no inputs provided, derive the addresses from the seed and
                //  confirm that the inputs exceed the threshold
                else
                {
                    List <Input> inputList = GetInputs(seed, 0, 0, (int)totalValue).InputsList;
                    return(AddRemainder(seed, inputList, bundle, tag, totalValue, remainderAddress, signatureFragments));
                }
            }
            else
            {
                // If no input required, don't sign and simply finalize the bundle
                bundle.FinalizeBundle(curl);
                bundle.AddTrytes(signatureFragments);

                List <String> bundleTrytes = new List <string>();
                bundle.Transactions.ForEach(tx => bundleTrytes.Add(tx.ToTransactionTrytes()));

                bundleTrytes.Reverse();
                return(bundleTrytes);
            }
        }