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