/// <summary> /// Internal implementation for Single Transfer Crypto /// Returns either a receipt or record or throws /// an exception. /// </summary> private async Task <TResult> TransferTokenImplementationAsync <TResult>(Address token, Address fromAddress, Address toAddress, long amount, Signatory?signatory, Action <IContext>?configure) where TResult : new() { amount = RequireInputParameter.Amount(amount); var transactions = new List <TokenTransferList>(1); var xferList = new TokenTransferList { Token = new TokenID(RequireInputParameter.Token(token)) }; xferList.Transfers.Add(new AccountAmount { AccountID = new AccountID(RequireInputParameter.FromAddress(fromAddress)), Amount = -amount }); xferList.Transfers.Add(new AccountAmount { AccountID = new AccountID(RequireInputParameter.ToAddress(toAddress)), Amount = amount }); transactions.Add(xferList); return(await TransferImplementationAsync <TResult>(null, transactions, signatory, configure)); }
internal static IEnumerable <TokenTransferList> TokenTransferList(IEnumerable <TokenTransfer> tokenTransfers) { if (tokenTransfers is null) { throw new ArgumentNullException(nameof(tokenTransfers), "The list of token transfers can not be null."); } var transactions = new List <TokenTransferList>(); foreach (var tokenGroup in tokenTransfers.GroupBy(txfer => txfer.Token)) { if (tokenGroup.Key.IsNullOrNone()) { throw new ArgumentException("Token", "The list of token transfers cannot contain a null or empty Token value."); } long sum = 0; var netRequests = new Dictionary <Address, long>(); foreach (var xfer in tokenGroup) { if (xfer.Address.IsNullOrNone()) { throw new ArgumentException(nameof(xfer.Address), "The list of token transfers cannot contain a null or empty account value."); } if (xfer.Amount == 0) { throw new ArgumentOutOfRangeException(nameof(xfer.Amount), $"The amount to transfer tokens to/from {xfer.Address.ShardNum}.{xfer.Address.RealmNum}.{xfer.Address.AccountNum} must be a value, negative for transfers out, and positive for transfers in. A value of zero is not allowed."); } if (netRequests.TryGetValue(xfer.Address, out long value)) { netRequests[xfer.Address] = value + xfer.Amount; } else { netRequests[xfer.Address] = xfer.Amount; } sum += xfer.Amount; } if (sum != 0) { throw new ArgumentOutOfRangeException(nameof(tokenTransfers), $"The sum of token sends and receives for {tokenGroup.Key.ShardNum}.{tokenGroup.Key.RealmNum}.{tokenGroup.Key.AccountNum} does not balance."); } var xferList = new TokenTransferList { Token = new TokenID(tokenGroup.Key) }; foreach (var netTransfer in netRequests) { if (netTransfer.Value != 0) { xferList.Transfers.Add(new AccountAmount { AccountID = new AccountID(netTransfer.Key), Amount = netTransfer.Value }); } } if (xferList.Transfers.Count > 0) { transactions.Add(xferList); } } if (transactions.Count == 0) { throw new ArgumentOutOfRangeException(nameof(tokenTransfers), "The dictionary of token transfers can not be empty."); } return(transactions); }
internal CryptoTransferTransactionBody(TransferParams transfers) : this() { if (transfers == null) { throw new ArgumentNullException(nameof(transfers), "The transfer parametes cannot not be null."); } var missingTransfers = true; if (transfers.CryptoTransfers is not null) { long sum = 0; var netRequests = new Dictionary <AddressOrAlias, long>(); foreach (var transfer in transfers.CryptoTransfers) { if (transfer.Value == 0) { throw new ArgumentOutOfRangeException(nameof(transfers.CryptoTransfers), $"The amount to transfer crypto to/from {transfer.Key} must be a value, negative for transfers out, and positive for transfers in. A value of zero is not allowed."); } if (netRequests.TryGetValue(transfer.Key, out long value)) { netRequests[transfer.Key] = value + transfer.Value; } else { netRequests[transfer.Key] = transfer.Value; } sum += transfer.Value; } if (netRequests.Count == 0) { throw new ArgumentOutOfRangeException(nameof(transfers.CryptoTransfers), "The dictionary of crypto transfers can not be empty."); } if (sum != 0) { throw new ArgumentOutOfRangeException(nameof(transfers.CryptoTransfers), "The sum of crypto sends and receives does not balance."); } var xferList = new TransferList(); foreach (var transfer in netRequests) { if (transfer.Value != 0) { xferList.AccountAmounts.Add(new AccountAmount(transfer.Key, transfer.Value)); } } missingTransfers = xferList.AccountAmounts.Count == 0; Transfers = xferList; } if (transfers.TokenTransfers is not null) { foreach (var tokenGroup in transfers.TokenTransfers.GroupBy(txfer => txfer.Token)) { if (tokenGroup.Key.IsNullOrNone()) { throw new ArgumentException("Token", "The list of token transfers cannot contain a null or empty Token value."); } long sum = 0; var netRequests = new Dictionary <AddressOrAlias, long>(); foreach (var xfer in tokenGroup) { if (xfer.Address.IsNullOrNone()) { throw new ArgumentException(nameof(xfer.Address), "The list of token transfers cannot contain a null or empty account value."); } if (xfer.Amount == 0) { throw new ArgumentOutOfRangeException(nameof(xfer.Amount), $"The amount to transfer tokens to/from {xfer.Address} must be a value, negative for transfers out, and positive for transfers in. A value of zero is not allowed."); } if (netRequests.TryGetValue(xfer.Address, out long value)) { netRequests[xfer.Address] = value + xfer.Amount; } else { netRequests[xfer.Address] = xfer.Amount; } sum += xfer.Amount; } if (sum != 0) { throw new ArgumentOutOfRangeException(nameof(transfers.TokenTransfers), $"The sum of token sends and receives for {tokenGroup.Key.ShardNum}.{tokenGroup.Key.RealmNum}.{tokenGroup.Key.AccountNum} does not balance."); } var xferList = new TokenTransferList { Token = new TokenID(tokenGroup.Key) }; foreach (var netTransfer in netRequests) { if (netTransfer.Value != 0) { xferList.Transfers.Add(new AccountAmount(netTransfer.Key, netTransfer.Value)); } } if (xferList.Transfers.Count > 0) { TokenTransfers.Add(xferList); } } } if (transfers.AssetTransfers is not null) { foreach (var tokenGroup in transfers.AssetTransfers.GroupBy(txfer => (Address)txfer.Asset)) { if (tokenGroup.Key.IsNullOrNone()) { throw new ArgumentException("Asset", "The list of asset token transfers cannot contain a null or empty Asset Token address."); } var netRequests = new Dictionary <long, AssetTransfer>(); foreach (var xfer in tokenGroup) { if (xfer.Asset.SerialNum <= 0) { throw new ArgumentException(nameof(xfer.Asset), "The list of asset transfers cannot contain an asset without a serial number."); } if (xfer.From.IsNullOrNone()) { throw new ArgumentException(nameof(xfer.From), "The list of asset transfers cannot contain a null or empty from account value."); } if (xfer.To.IsNullOrNone()) { throw new ArgumentException(nameof(xfer.From), "The list of asset transfers cannot contain a null or empty to account value."); } if (netRequests.ContainsKey(xfer.Asset.SerialNum)) { throw new ArgumentException(nameof(xfer.Asset), "The list of asset transfers cannot contain the same asset in multiple transfers at once."); } else { netRequests[xfer.Asset.SerialNum] = xfer; } } if (netRequests.Count > 0) { var xferList = new TokenTransferList { Token = new TokenID(tokenGroup.Key) }; foreach (var netTransfer in netRequests) { xferList.NftTransfers.Add(new NftTransfer(netTransfer.Value)); } TokenTransfers.Add(xferList); } } } missingTransfers &= TokenTransfers.Count == 0; if (missingTransfers) { throw new ArgumentException(nameof(transfers), "Both crypto, token and asset transfer lists are null or empty. At least one must include net transfers."); } }