Пример #1
0
        private List <string> AddRemainder(string seed, List <Input> inputs, Bundle bundle, string tag, long totalValue,
                                           string remainderAddress, List <string> signatureFragments)
        {
            long totalTransferValue = totalValue;

            foreach (Input input in inputs)
            {
                var thisBalance = input.Balance;
                var toSubtract  = 0 - thisBalance;
                var timestamp   = IotaApiUtils.CreateTimeStampNow();

                // Add input as bundle entry
                bundle.AddEntry(2, input.Address, toSubtract, tag, timestamp);
                // If there is a remainder value
                // Add extra output to send remaining funds to

                if (thisBalance >= totalTransferValue)
                {
                    var remainder = thisBalance - totalTransferValue;

                    // If user has provided remainder address
                    // Use it to send remaining funds to
                    if (remainder > 0 && remainderAddress != null)
                    {
                        // Remainder bundle entry
                        bundle.AddEntry(1, remainderAddress, remainder, tag, timestamp);

                        // function for signing inputs
                        IotaApiUtils.SignInputsAndReturn(seed, inputs, bundle, signatureFragments, curl);
                    }
                    else if (remainder > 0)
                    {
                        // Generate a new Address by calling getNewAddress
                        string address = GetNewAddress(seed)[0];

                        // Remainder bundle entry
                        bundle.AddEntry(1, address, remainder, tag, timestamp);

                        // function for signing inputs
                        return(IotaApiUtils.SignInputsAndReturn(seed, inputs, bundle, signatureFragments, curl));
                    }
                    else
                    {
                        // If there is no remainder, do not add transaction to bundle
                        // simply sign and return
                        return(IotaApiUtils.SignInputsAndReturn(seed, inputs, bundle, signatureFragments, curl));
                    }
                }
                // If multiple inputs provided, subtract the totalTransferValue by
                // the inputs balance
                else
                {
                    totalTransferValue -= thisBalance;
                }
            }

            throw new NotEnoughBalanceException(totalValue);
        }
Пример #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="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);
        }
Пример #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="securitySum"></param>
        /// <param name="inputAddress"></param>
        /// <param name="remainderAddress"></param>
        /// <param name="transfers"></param>
        /// <param name="testMode"></param>
        /// <returns></returns>
        public List <Transaction> InitiateTransfer(
            int securitySum, string inputAddress, string remainderAddress,
            List <Transfer> transfers, bool testMode)
        {
            // validate input address
            if (!InputValidator.IsAddress(inputAddress))
            {
                throw new ArgumentException("Invalid addresses provided.");
            }

            // validate remainder address
            if (remainderAddress != null && !InputValidator.IsAddress(remainderAddress))
            {
                throw new ArgumentException("Invalid addresses provided.");
            }

            // Input validation of transfers object
            if (!InputValidator.IsTransfersCollectionValid(transfers))
            {
                throw new ArgumentException("Invalid transfers provided.");
            }

            // Create a new bundle
            Bundle bundle = new Bundle();

            long          totalValue         = 0;
            List <String> signatureFragments = new List <string>();
            String        tag = "";

            //

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

                int signatureMessageLength = 1;

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

                    String msgCopy = transfer.Message;

                    // While there is still a message, copy it

                    while (!string.IsNullOrEmpty(msgCopy))
                    {
                        string fragment = msgCopy.Substring(0, Constants.MessageLength);
                        msgCopy = msgCopy.Substring(Constants.MessageLength, msgCopy.Length - Constants.MessageLength);

                        // Pad remainder of fragment
                        fragment = fragment.PadRight(Constants.MessageLength, '9');


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

                    if (transfer.Message.Length < Constants.MessageLength)
                    {
                        fragment = fragment.PadRight(Constants.MessageLength, '9');
                    }

                    signatureFragments.Add(fragment);
                }

                tag = transfer.Tag;

                // pad for required 27 tryte length
                if (transfer.Tag.Length < Constants.TagLength)
                {
                    tag = tag.PadRight(Constants.TagLength, '9');
                }

                // get current timestamp in seconds
                long timestamp = (long)Math.Floor(GetCurrentTimestampInSeconds());

                // Add first entry to the bundle
                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)
            {
                GetBalancesResponse balancesResponse = GetBalances(new List <string> {
                    inputAddress
                }, 100);
                var balances = balancesResponse.Balances;

                long totalBalance = 0;

                foreach (var balance in balances)
                {
                    totalBalance += balance;
                }

                // get current timestamp in seconds
                long timestamp = (long)Math.Floor(GetCurrentTimestampInSeconds());

                // bypass the balance checks during unit testing
                if (testMode)
                {
                    totalBalance += 1000;
                }

                if (totalBalance > 0)
                {
                    long toSubtract = 0 - totalBalance;

                    // Add input as bundle entry
                    // Only a single entry, signatures will be added later
                    bundle.AddEntry(securitySum, inputAddress, toSubtract, tag, timestamp);
                }
                // Return not enough balance error
                if (totalValue > totalBalance)
                {
                    throw new IllegalStateException("Not enough balance.");
                }

                // If there is a remainder value
                // Add extra output to send remaining funds to
                if (totalBalance > totalValue)
                {
                    long remainder = totalBalance - totalValue;

                    // Remainder bundle entry if necessary
                    if (remainderAddress == null)
                    {
                        throw new IllegalStateException("No remainder address defined.");
                    }

                    bundle.AddEntry(1, remainderAddress, remainder, tag, timestamp);
                }

                bundle.FinalizeBundle(new Curl(CurlMode.CurlP81));
                bundle.AddTrytes(signatureFragments);

                return(bundle.Transactions);
            }
            else
            {
                throw new System.Exception("Invalid value transfer: the transfer does not require a signature.");
            }
        }
Пример #4
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);
            }
        }
Пример #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="seed"></param>
        /// <param name="security"></param>
        /// <param name="transfers"></param>
        /// <param name="remainder"></param>
        /// <param name="inputs"></param>
        /// <param name="tips"></param>
        /// <param name="validateInputs"></param>
        /// <returns></returns>
        public List <string> PrepareTransfers(
            string seed, int security,
            Transfer[] transfers,
            string remainder,
            Input[] inputs,
            Transaction[] tips,
            bool validateInputs)
        {
            // validate seed
            if (!InputValidator.IsValidSeed(seed))
            {
                throw new IllegalStateException(Constants.INVALID_SEED_INPUT_ERROR);
            }


            if (!InputValidator.IsValidSecurityLevel(security))
            {
                throw new ArgumentException(Constants.INVALID_SECURITY_LEVEL_INPUT_ERROR);
            }

            if (remainder != null && !InputValidator.IsAddress(remainder))
            {
                throw new ArgumentException(Constants.INVALID_ADDRESSES_INPUT_ERROR);
            }

            // Input validation of transfers object
            if (!InputValidator.IsValidTransfersCollection(transfers.ToList()))
            {
                throw new ArgumentException(Constants.INVALID_TRANSFERS_INPUT_ERROR);
            }

            if (inputs != null && !InputValidator.IsValidInputsCollection(inputs))
            {
                throw new ArgumentException(Constants.INVALID_ADDRESSES_INPUT_ERROR);
            }

            // 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.MESSAGE_LENGTH)
                {
                    // Get total length, message / maxLength (2187 trytes)
                    signatureMessageLength +=
                        (int)Math.Floor((double)transfer.Message.Length / Constants.MESSAGE_LENGTH);

                    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(fragment.Length, msgCopy.Length - fragment.Length);

                        // Pad remainder of fragment
                        if (fragment.Length < 2187)
                        {
                            fragment = fragment.PadRight(2187, '9');
                        }

                        signatureFragments.Add(fragment);
                    }
                }
                else
                {
                    // Else, get single fragment with 2187 of 9's trytes
                    var fragment = transfer.Message.PadRight(Constants.MESSAGE_LENGTH, '9');

                    signatureFragments.Add(fragment);
                }

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

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

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

                // Pad for required 27 tryte length
                if (tag.Length < Constants.TAG_LENGTH)
                {
                    tag = tag.PadRight(Constants.TAG_LENGTH, '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)
            {
                // validate seed
                if (!InputValidator.IsValidSeed(seed))
                {
                    throw new IllegalStateException(Constants.INVALID_SEED_INPUT_ERROR);
                }


                //  Case 1: user provided inputs
                //  Validate the inputs by calling getBalances
                if (inputs != null && inputs.Length > 0)
                {
                    if (!validateInputs)
                    {
                        return(AddRemainder(seed, security, inputs.ToList(), bundle, tag, totalValue, remainder,
                                            signatureFragments));
                    }

                    // Get list if addresses of the provided inputs
                    var inputAddresses = new List <string>();
                    foreach (var input in inputs)
                    {
                        inputAddresses.Add(input.Address);
                    }

                    List <string> tipHashes = null;
                    if (tips != null)
                    {
                        tipHashes = new List <string>();
                        foreach (var tx in tips)
                        {
                            tipHashes.Add(tx.CurlHash());
                        }
                    }

                    var balances = IotaClient.GetBalances(100, inputAddresses, tipHashes);

                    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);

                            // if we've already reached the intended input value, break out of loop
                            if (totalBalance >= totalValue)
                            {
                                Log.Info("Total balance already reached ");
                                break;
                            }
                        }
                    }

                    // Return not enough balance error
                    if (totalValue > totalBalance)
                    {
                        throw new IllegalStateException(Constants.NOT_ENOUGH_BALANCE_ERROR);
                    }

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

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

            // If no input required, don't sign and simply finalize the bundle
            bundle.FinalizeBundle(SpongeFactory.Create(SpongeFactory.Mode.KERL));
            bundle.AddTrytes(signatureFragments);

            var bundleTrytes = new List <string>();

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

            bundleTrytes.Reverse();
            return(bundleTrytes);
        }
Пример #6
0
        private List <string> AddRemainder(
            string seed,
            int security,
            List <Input> inputs,
            Bundle bundle,
            string tag,
            long totalValue,
            string remainderAddress,
            List <string> signatureFragments)
        {
            var totalTransferValue = totalValue;

            foreach (var input in inputs)
            {
                var thisBalance = input.Balance;
                var toSubtract  = 0 - thisBalance;
                var timestamp   = TimeStamp.Now();

                // Add input as bundle entry
                // use input.Security
                bundle.AddEntry(input.Security, input.Address, toSubtract, tag, timestamp);
                // If there is a remainder value
                // Add extra output to send remaining funds to

                if (thisBalance >= totalTransferValue)
                {
                    var remainder = thisBalance - totalTransferValue;

                    // If user has provided remainder address
                    // Use it to send remaining funds to
                    if (remainder > 0 && remainderAddress != null)
                    {
                        // Remainder bundle entry
                        bundle.AddEntry(1, remainderAddress, remainder, tag, timestamp);

                        // function for signing inputs
                        return(IotaApiUtils.SignInputsAndReturn(
                                   seed, inputs, bundle, signatureFragments,
                                   SpongeFactory.Create(SpongeFactory.Mode.KERL)));
                    }

                    if (remainder > 0)
                    {
                        AddressRequest addressRequest = new AddressRequest(seed, security);
                        var            res            = GenerateNewAddresses(addressRequest);

                        // Remainder bundle entry
                        bundle.AddEntry(1, res.Addresses[0], remainder, tag, timestamp);

                        // function for signing inputs
                        return(IotaApiUtils.SignInputsAndReturn(
                                   seed, inputs, bundle, signatureFragments,
                                   SpongeFactory.Create(SpongeFactory.Mode.KERL)));
                    }

                    // If there is no remainder, do not add transaction to bundle
                    // simply sign and return
                    return(IotaApiUtils.SignInputsAndReturn(
                               seed, inputs, bundle, signatureFragments,
                               SpongeFactory.Create(SpongeFactory.Mode.KERL)));
                }

                // If multiple inputs provided, subtract the totalTransferValue by
                // the inputs balance
                totalTransferValue -= thisBalance;
            }

            throw new IllegalStateException(Constants.NOT_ENOUGH_BALANCE_ERROR);
        }