示例#1
0
        /// <summary>
        /// Transfer NEP5 tokens.
        /// </summary>
        /// <param name="attributes"></param>
        /// <param name="outputs"></param>
        /// <param name="changeAddress"></param>
        /// <param name="fee"></param>
        /// <returns></returns>
        public override async Task <Transaction> TransferNep5(List <TransactionAttribute> attributes,
                                                              IEnumerable <TransferOutput> outputs,
                                                              UInt160 changeAddress = null, decimal fee = 0)
        {
            InvocationTransaction tx;
            var cOutputs = outputs.Where(p => !p.IsGlobalAsset).GroupBy(p => new
            {
                AssetId = (UInt160)p.AssetId,
                Account = p.ScriptHash
            }, (k, g) => new
            {
                k.AssetId,
                Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value),
                k.Account
            }).ToArray();

            if (cOutputs.Length == 0)
            {
                return(null);
            }
            var nep5Balances = await TransactionBuilderHelper.GetNep5Balances(AddressScriptHash.ToAddress(), _restService);

            using (ScriptBuilder sb = new ScriptBuilder())
            {
                foreach (var output in cOutputs)
                {
                    var nep5Balance = nep5Balances.SingleOrDefault(x => x.AssetHash == output.AssetId.ToString().Remove(0, 2));
                    if (nep5Balance == null)
                    {
                        throw new WalletException($"Not enough balance of: {output.AssetId} ");
                    }
                    sb.EmitAppCall(output.AssetId, Nep5Methods.transfer.ToString(), AddressScriptHash, output.Account, output.Value);
                    sb.Emit(OpCode.THROWIFNOT);
                }

                byte[] nonce = GenerateNonce(8);
                sb.Emit(OpCode.RET, nonce);
                tx = new InvocationTransaction
                {
                    Version = 1,
                    Script  = sb.ToArray()
                };
            }

            if (attributes == null)
            {
                attributes = new List <TransactionAttribute>();
            }
            attributes.Add(new TransactionAttribute
            {
                Usage = TransactionAttributeUsage.Script,
                Data  = AddressScriptHash.ToArray()
            });

            tx.Attributes = attributes.ToArray();
            tx.Inputs     = new CoinReference[0];
            tx.Outputs    = outputs.Where(p => p.IsGlobalAsset).Select(p => p.ToTxOutput()).ToArray();
            tx.Witnesses  = new Witness[0];

            var gasConsumed = await EstimateGasAsync(tx.Script.ToHexString()); //todo add gas limit

            tx.Gas = InvocationTransaction.GetGas(Fixed8.FromDecimal(gasConsumed));

            tx = MakeTransaction(tx, AddressScriptHash, changeAddress, Fixed8.FromDecimal(fee));
            var success = await SignAndSendTransaction(tx);

            return(success ? tx : null);
        }