Exemplo n.º 1
0
        public async Task <object> TestingTransfer(string from, string privateKey, string to, IAsset asset, decimal amount)
        {
            var nodeHttp    = new NodeHttp(_nemUrl);
            var networkType = await nodeHttp.GetNetworkType();

            var networkTime    = (int)(await nodeHttp.GetExtendedNodeInfo()).NisInfo.CurrentTime;
            var toAddressParts = to.Split(AddressSeparator);
            var message        = toAddressParts.Length > 1
                ? PlainMessage.Create(toAddressParts[1]) as IMessage
                : EmptyMessage.Create();
            var mosaic = Mosaic.CreateFromIdentifier(asset.AssetId, (ulong)asset.ToBaseUnit(amount));
            var fee    = await TransferTransaction.CalculateFee(networkType, message, new[] { mosaic }, new NamespaceMosaicHttp(_nemUrl));

            var tx = TransferTransaction.Create(
                networkType,
                new Deadline(networkTime + _expiresInSeconds),
                fee.fee,
                Address.CreateFromEncoded(toAddressParts[0]),
                new List <Mosaic> {
                mosaic
            },
                message,
                networkTime);
            var signed = tx.SignWith(KeyPair.CreateFromPrivateKey(privateKey));
            var result = await new TransactionHttp(_nemUrl).Announce(signed);

            return(result);
        }
Exemplo n.º 2
0
        public async Task <(string transactionContext, decimal fee, long expiration)> BuildTransactionAsync(Guid operationId,
                                                                                                            IAsset asset, IReadOnlyList <IOperationAction> actions, bool includeFee)
        {
            // from one side NEM supports single sender and single receiver per transaction,
            // from the other side we support single asset per transaction,
            // finally only single transfers are allowed

            if (actions.Count != 1)
            {
                throw new ArgumentException("Transaction must contain a single transfer only");
            }

            var nodeHttp    = new NodeHttp(_nemUrl);
            var networkType = await nodeHttp.GetNetworkType();

            var action         = actions[0];
            var toAddressParts = action.To.Split(AddressSeparator);
            var toAddress      = toAddressParts[0];
            var memo           = toAddressParts.Length > 1
                ? toAddressParts[1]
                : "";
            var message = !string.IsNullOrEmpty(memo)
                ? PlainMessage.Create(memo) as IMessage
                : EmptyMessage.Create();
            var mosaic = Mosaic.CreateFromIdentifier(asset.AssetId, (ulong)asset.ToBaseUnit(action.Amount));
            var fee    = await TransferTransaction.CalculateFee(networkType, message, new[] { mosaic }, new NamespaceMosaicHttp(_nemUrl));

            if (includeFee)
            {
                try
                {
                    checked
                    {
                        if (mosaic.NamespaceName == Xem.NamespaceName &&
                            mosaic.MosaicName == Xem.MosaicName)
                        {
                            mosaic.Amount -= fee.fee;
                        }

                        // only single transfers are supported,
                        // so there must be single levy

                        var levy = fee.levies.SingleOrDefault();

                        if (levy != null &&
                            mosaic.NamespaceName == levy.NamespaceName &&
                            mosaic.MosaicName == levy.MosaicName)
                        {
                            mosaic.Amount -= levy.Amount;
                        }
                    }
                }
                catch (OverflowException)
                {
                    throw new BlockchainException(BlockchainErrorCode.AmountIsTooSmall, "Amount is less than fee");
                }
            }

            // check balances of FromAddress for all required assets

            var fromAddress = action.From.Split(AddressSeparator)[0];
            var owned       = await new AccountHttp(_nemUrl).MosaicsOwned(Address.CreateFromEncoded(fromAddress));
            var required    = fee.levies
                              .Append(Xem.CreateAbsolute(fee.fee))
                              .Append(mosaic)
                              .GroupBy(m => new { m.NamespaceName, m.MosaicName })
                              .Select(g => new Mosaic(g.Key.NamespaceName, g.Key.MosaicName, g.Aggregate(0UL, (v, m) => v += m.Amount)))
                              .ToList();

            foreach (var req in required)
            {
                var own = owned.FirstOrDefault(m => m.NamespaceName == req.NamespaceName && m.MosaicName == req.MosaicName)?.Amount ?? 0UL;
                if (own < req.Amount)
                {
                    throw new BlockchainException(BlockchainErrorCode.NotEnoughBalance,
                                                  $"Not enough {req.NamespaceName}:{req.MosaicName}");
                }
            }

            var networkTime = (int)(await nodeHttp.GetExtendedNodeInfo()).NisInfo.CurrentTime;

            var tx = TransferTransaction.Create(
                networkType,
                new Deadline(networkTime + _expiresInSeconds),
                fee.fee,
                Address.CreateFromEncoded(toAddress),
                new List <Mosaic> {
                mosaic
            },
                message,
                networkTime);

            return(
                tx.ToJson(),
                Convert.ToDecimal(fee.fee * 1e-6),
                tx.Deadline.GetInstant()
                );
        }