示例#1
0
        /// <summary>
        /// Method that SendNativeAsset, TransferNep5 and CallContract uses to create the inputs and outputs of the transaction.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tx"></param>
        /// <param name="from"></param>
        /// <param name="changeAddress"></param>
        /// <param name="fee"></param>
        /// <returns></returns>
        private T MakeTransaction <T>(T tx, UInt160 from = null, UInt160 changeAddress = null, Fixed8 fee = default(Fixed8)) where T : Transaction
        {
            if (tx.Outputs == null)
            {
                tx.Outputs = new TransactionOutput[0];
            }
            if (tx.Attributes == null)
            {
                tx.Attributes = new TransactionAttribute[0];
            }
            if (from == null)
            {
                from = AddressScriptHash;
            }
            fee += tx.SystemFee;
            var payTotal = tx.Outputs.GroupBy(p => p.AssetId, (k, g) => new
            {
                AssetId = k,
                Value   = g.Sum(p => p.Value)
            }).ToDictionary(p => p.AssetId);

            if (fee > Fixed8.Zero)
            {
                if (payTotal.ContainsKey(Utils.GasToken))
                {
                    payTotal[Utils.GasToken] = new
                    {
                        AssetId = Utils.GasToken,
                        Value   = payTotal[Utils.GasToken].Value + fee
                    };
                }
                else
                {
                    payTotal.Add(Utils.GasToken, new
                    {
                        AssetId = Utils.GasToken,
                        Value   = fee
                    });
                }
            }

            var payCoins = payTotal.Select(async p => new
            {
                AssetId  = p.Key,
                Unspents = await TransactionBuilderHelper.FindUnspentCoins(p.Key, p.Value.Value, from, _restService)
            }).Select(x => x.Result).ToDictionary(p => p.AssetId);

            if (payCoins.Any(p => p.Value.Unspents == null))
            {
                return(null);
            }

            var inputSum = payCoins.Values.ToDictionary(p => p.AssetId, p => new
            {
                p.AssetId,
                Value = p.Unspents.Sum(q => q.Output.Value)
            });

            if (changeAddress == null)
            {
                changeAddress = from;
            }
            List <TransactionOutput> outputsNew = new List <TransactionOutput>(tx.Outputs);

            foreach (UInt256 assetId in inputSum.Keys)
            {
                if (inputSum[assetId].Value > payTotal[assetId].Value)
                {
                    outputsNew.Add(new TransactionOutput
                    {
                        AssetId    = assetId,
                        Value      = inputSum[assetId].Value - payTotal[assetId].Value,
                        ScriptHash = changeAddress
                    });
                }
            }
            tx.Inputs  = payCoins.Values.SelectMany(p => p.Unspents).Select(p => p.Reference).ToArray();
            tx.Outputs = outputsNew.ToArray();
            return(tx);
        }