예제 #1
0
 private static DepositDetails GetDepositDetails(DataAssetUnitType unitType = DataAssetUnitType.Unit,
                                                 uint confirmationTimestamp = DepositConfirmationTimestamp)
 => new DepositDetails(new Deposit(Keccak.Zero, 1, 1, 1),
                       GetDataAsset(unitType), TestItem.AddressB, Array.Empty <byte>(), 1,
                       new [] { TransactionInfo.Default(TestItem.KeccakA, 1, 1, 1, 1) }, confirmationTimestamp);
예제 #2
0
        public async Task <RefundClaimStatus> TryClaimEarlyRefundAsync(DepositDetails deposit, Address refundTo)
        {
            ulong now = _timestamper.EpochSeconds;

            if (!deposit.CanClaimEarlyRefund(now, deposit.Timestamp))
            {
                return(RefundClaimStatus.Empty);
            }

            Block?latestBlock = await _blockchainBridge.GetLatestBlockAsync();

            if (latestBlock == null)
            {
                return(RefundClaimStatus.Empty);
            }

            now = (ulong)latestBlock.Timestamp;
            if (!deposit.CanClaimEarlyRefund(now, deposit.Timestamp))
            {
                return(RefundClaimStatus.Empty);
            }

            Keccak depositId       = deposit.Deposit.Id;
            Keccak?transactionHash = deposit.ClaimedRefundTransaction?.Hash;

            if (transactionHash is null)
            {
                Address provider = deposit.DataAsset.Provider.Address;
                if (deposit.EarlyRefundTicket == null)
                {
                    throw new InvalidDataException($"Early refund ticket is null on a claimable deposit {depositId}");
                }

                EarlyRefundTicket ticket           = deposit.EarlyRefundTicket;
                EarlyRefundClaim  earlyRefundClaim = new EarlyRefundClaim(ticket.DepositId, deposit.DataAsset.Id,
                                                                          deposit.Deposit.Units, deposit.Deposit.Value, deposit.Deposit.ExpiryTime, deposit.Pepper, provider,
                                                                          ticket.ClaimableAfter, ticket.Signature, refundTo);
                UInt256 gasPrice = await _gasPriceService.GetCurrentRefundAsync();

                transactionHash = await _refundService.ClaimEarlyRefundAsync(refundTo, earlyRefundClaim, gasPrice);

                if (transactionHash is null)
                {
                    if (_logger.IsError)
                    {
                        _logger.Error("There was an error when trying to claim early refund (no transaction hash returned).");
                    }
                    return(RefundClaimStatus.Empty);
                }

                deposit.AddClaimedRefundTransaction(TransactionInfo.Default(transactionHash, 0, gasPrice,
                                                                            _refundService.GasLimit, _timestamper.EpochSeconds));
                await _depositRepository.UpdateAsync(deposit);

                if (_logger.IsInfo)
                {
                    _logger.Info($"Claimed an early refund for deposit: '{depositId}', gas price: {gasPrice} wei, transaction hash: '{transactionHash}' (awaits a confirmation).");
                }
            }

            bool confirmed = await TryConfirmClaimAsync(deposit, "early ");

            return(confirmed
                ? RefundClaimStatus.Confirmed(transactionHash)
                : RefundClaimStatus.Unconfirmed(transactionHash));
        }
예제 #3
0
 private static DepositDetails GetDepositDetails()
 => new DepositDetails(new Deposit(Keccak.OfAnEmptyString, 1, 1, 1),
                       GetDataAsset(), TestItem.AddressB, Array.Empty <byte>(), 1,
                       new [] { TransactionInfo.Default(TestItem.KeccakA, 1, 1, 1, 1) },
                       earlyRefundTicket: new EarlyRefundTicket(Keccak.OfAnEmptyString, 1, null));
예제 #4
0
        public async Task <RefundClaimStatus> TryClaimRefundAsync(DepositDetails deposit, Address refundTo)
        {
            ulong now = _timestamper.UnixTime.Seconds;

            if (!deposit.CanClaimRefund(now))
            {
                DisplayRefundInfo(deposit, now);
                return(RefundClaimStatus.Empty);
            }

            Block?latestBlock = await _blockchainBridge.GetLatestBlockAsync();

            if (latestBlock == null)
            {
                return(RefundClaimStatus.Empty);
            }

            now = (ulong)latestBlock.Timestamp;
            if (!deposit.CanClaimRefund(now))
            {
                DisplayRefundInfo(deposit, now);
                return(RefundClaimStatus.Empty);
            }

            Keccak depositId       = deposit.Deposit.Id;
            Keccak?transactionHash = deposit.ClaimedRefundTransaction?.Hash;

            if (transactionHash is null)
            {
                Address     provider    = deposit.DataAsset.Provider.Address;
                RefundClaim refundClaim = new RefundClaim(depositId, deposit.DataAsset.Id, deposit.Deposit.Units,
                                                          deposit.Deposit.Value, deposit.Deposit.ExpiryTime, deposit.Pepper, provider, refundTo);
                UInt256 gasPrice = await _gasPriceService.GetCurrentRefundGasPriceAsync();

                transactionHash = await _refundService.ClaimRefundAsync(refundTo, refundClaim, gasPrice);

                if (transactionHash is null)
                {
                    if (_logger.IsError)
                    {
                        _logger.Error("There was an error when trying to claim refund (no transaction hash returned).");
                    }
                    return(RefundClaimStatus.Empty);
                }

                deposit.AddClaimedRefundTransaction(TransactionInfo.Default(transactionHash, 0, gasPrice,
                                                                            _refundService.GasLimit, _timestamper.UnixTime.Seconds));
                await _depositRepository.UpdateAsync(deposit);

                if (_logger.IsInfo)
                {
                    _logger.Info($"Claimed a refund for deposit: '{depositId}', gas price: {gasPrice} wei, transaction hash: '{transactionHash}' (awaits a confirmation).");
                }
            }

            bool confirmed = await TryConfirmClaimAsync(deposit, string.Empty);

            return(confirmed
                ? RefundClaimStatus.Confirmed(transactionHash)
                : RefundClaimStatus.Unconfirmed(transactionHash));
        }
        private IEnumerable <PaymentClaim> GetPaymentClaims()
        {
            yield return(new PaymentClaim(
                             id: TestItem.KeccakA,
                             depositId: TestItem.KeccakB,
                             assetId: TestItem.KeccakC,
                             assetName: "asset1",
                             units: 1,
                             claimedUnits: 2,
                             unitsRange: new UnitsRange(1, 2),
                             value: 4,
                             claimedValue: 5,
                             expiryTime: 6,
                             pepper: new byte[] { 1, 2, 3 },
                             provider: TestItem.AddressA,
                             consumer: TestItem.AddressB,
                             signature: new Signature(1, 2, 37),
                             timestamp: 7,
                             transactions: Enumerable.Empty <TransactionInfo>(),
                             status: PaymentClaimStatus.Claimed));

            yield return(new PaymentClaim(
                             id: TestItem.KeccakB,
                             depositId: TestItem.KeccakA,
                             assetId: TestItem.KeccakD,
                             assetName: "asset2",
                             units: 1,
                             claimedUnits: 2,
                             unitsRange: new UnitsRange(1, 2),
                             value: 4,
                             claimedValue: 5,
                             expiryTime: 6,
                             pepper: new byte[] { 1, 2, 3 },
                             provider: TestItem.AddressA,
                             consumer: TestItem.AddressC,
                             signature: new Signature(1, 2, 37),
                             timestamp: 7,
                             transactions: Enumerable.Empty <TransactionInfo>(),
                             status: PaymentClaimStatus.Cancelled));

            yield return(new PaymentClaim(
                             id: TestItem.KeccakC,
                             depositId: TestItem.KeccakF,
                             assetId: TestItem.KeccakE,
                             assetName: "asset3",
                             units: 1,
                             claimedUnits: 2,
                             unitsRange: new UnitsRange(1, 2),
                             value: 4,
                             claimedValue: 5,
                             expiryTime: 6,
                             pepper: new byte[] { 1, 2, 3 },
                             provider: TestItem.AddressA,
                             consumer: TestItem.AddressD,
                             signature: new Signature(1, 2, 37),
                             timestamp: 7,
                             transactions: Enumerable.Empty <TransactionInfo>(),
                             status: PaymentClaimStatus.Sent));

            yield return(new PaymentClaim(
                             id: TestItem.KeccakD,
                             depositId: TestItem.KeccakE,
                             assetId: TestItem.KeccakF,
                             assetName: "asset4",
                             units: 1,
                             claimedUnits: 2,
                             unitsRange: new UnitsRange(1, 2),
                             value: 4,
                             claimedValue: 5,
                             expiryTime: 6,
                             pepper: new byte[] { 1, 2, 3 },
                             provider: TestItem.AddressA,
                             consumer: TestItem.AddressA,
                             signature: new Signature(1, 2, 37),
                             timestamp: 7,
                             transactions: new TransactionInfo[] { TransactionInfo.Default(Keccak.Zero, value: 10, gasPrice: 1, gasLimit: 100, timestamp: 10) },
                             status: PaymentClaimStatus.Sent));
        }
예제 #6
0
 private static DepositDetails GetDepositDetails()
 => new DepositDetails(new Deposit(Keccak.OfAnEmptyString, 1, DepositExpiryTime, 1),
                       GetDataAsset(), TestItem.AddressB, Array.Empty <byte>(), 1,
                       new[] { TransactionInfo.Default(TestItem.KeccakA, 1, 1, 1, 1) });
        public async Task <PaymentClaim?> ProcessAsync(DataDeliveryReceiptRequest receiptRequest, Signature signature)
        {
            Keccak   depositId = receiptRequest.DepositId;
            Consumer?consumer  = await _consumerRepository.GetAsync(depositId);

            if (consumer is null)
            {
                if (_logger.IsError)
                {
                    _logger.Error($"Could not find any consumers for deposit {depositId} in the repository.");
                }
                return(null);
            }

            DataRequest  dataRequest   = consumer.DataRequest;
            UnitsRange   range         = receiptRequest.UnitsRange;
            uint         claimedUnits  = range.Units;
            BigInteger   claimedValue  = claimedUnits * (BigInteger)consumer.DataRequest.Value / consumer.DataRequest.Units;
            ulong        timestamp     = _timestamper.UnixTime.Seconds;
            Rlp          unitsRangeRlp = _unitsRangeRlpDecoder.Encode(range);
            Keccak       id            = Keccak.Compute(Rlp.Encode(Rlp.Encode(depositId), Rlp.Encode(timestamp), unitsRangeRlp).Bytes);
            PaymentClaim paymentClaim  = new PaymentClaim(id, consumer.DepositId, consumer.DataAsset.Id,
                                                          consumer.DataAsset.Name, dataRequest.Units, claimedUnits, range, dataRequest.Value,
                                                          (UInt256)claimedValue, dataRequest.ExpiryTime, dataRequest.Pepper, dataRequest.Provider,
                                                          dataRequest.Consumer, signature, timestamp, Array.Empty <TransactionInfo>(), PaymentClaimStatus.Unknown);
            await _paymentClaimRepository.AddAsync(paymentClaim);

            if (_logger.IsInfo)
            {
                _logger.Info($"Claiming a payment (id: '{paymentClaim.Id}') for deposit: '{depositId}', range: [{range.From}, {range.To}], units: {claimedUnits}.");
            }
            UInt256 gasPrice = await _gasPriceService.GetCurrentPaymentClaimGasPriceAsync();

            Keccak?transactionHash = null;

            if (_disableSendingPaymentClaimTransaction)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn("*** NDM provider sending payment claim transaction is disabled ***");
                }
            }
            else
            {
                transactionHash = await SendTransactionAsync(paymentClaim, gasPrice);

                if (transactionHash is null)
                {
                    if (_logger.IsInfo)
                    {
                        _logger.Info($"Payment claim (id: {paymentClaim.Id}) for deposit: '{paymentClaim.DepositId}' did not receive a transaction hash.");
                    }
                    return(paymentClaim);
                }
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Payment claim (id: {paymentClaim.Id}) for deposit: '{paymentClaim.DepositId}' received a transaction hash: '{transactionHash}'.");
            }
            paymentClaim.AddTransaction(TransactionInfo.Default(transactionHash, 0, gasPrice, _paymentService.GasLimit,
                                                                timestamp));
            paymentClaim.SetStatus(PaymentClaimStatus.Sent);
            await _paymentClaimRepository.UpdateAsync(paymentClaim);

            string claimedEth = ((decimal)claimedValue / Eth).ToString("0.0000");

            if (_logger.IsInfo)
            {
                _logger.Info($"Sent a payment claim (id: '{paymentClaim.Id}') for deposit: '{depositId}', range: [{range.From}, {range.To}], units: {claimedUnits}, units: {claimedUnits}, value: {claimedValue} wei ({claimedEth} ETH, transaction hash: '{transactionHash}'.");
            }

            return(paymentClaim);
        }
예제 #8
0
        public async Task <Keccak?> MakeAsync(Keccak assetId, uint units, UInt256 value, Address address,
                                              UInt256?gasPrice = null)
        {
            if (!_wallet.IsUnlocked(address))
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Account: '{address}' is locked, can't make a deposit.");
                }

                return(null);
            }

            DataAsset?dataAsset = _dataAssetService.GetDiscovered(assetId);

            if (dataAsset is null)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Available data asset: '{assetId}' was not found.");
                }

                return(null);
            }

            if (!_dataAssetService.IsAvailable(dataAsset))
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Data asset: '{assetId}' is unavailable, state: {dataAsset.State}.");
                }

                return(null);
            }

            if (dataAsset.KycRequired && !await _kycVerifier.IsVerifiedAsync(assetId, address))
            {
                return(null);
            }

            Address  providerAddress = dataAsset.Provider.Address;
            INdmPeer?provider        = _providerService.GetPeer(providerAddress);

            if (provider is null)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Provider nodes were not found for address: '{providerAddress}'.");
                }

                return(null);
            }

            if (dataAsset.MinUnits > units || dataAsset.MaxUnits < units)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Invalid data request units: '{units}', min: '{dataAsset.MinUnits}', max: '{dataAsset.MaxUnits}'.");
                }

                return(null);
            }

            UInt256 unitsValue = units * dataAsset.UnitPrice;

            if (units * dataAsset.UnitPrice != value)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Invalid data request value: '{value}', while it should be: '{unitsValue}'.");
                }

                return(null);
            }

            uint now        = (uint)_timestamper.EpochSeconds;
            uint expiryTime = now + (uint)dataAsset.Rules.Expiry.Value;

            expiryTime += dataAsset.UnitType == DataAssetUnitType.Unit ? 0 : units;
            byte[] pepper  = _cryptoRandom.GenerateRandomBytes(16);
            byte[] abiHash = _abiEncoder.Encode(AbiEncodingStyle.Packed, _depositAbiSig, assetId.Bytes,
                                                units, value, expiryTime, pepper, dataAsset.Provider.Address, address);
            Keccak         depositId      = Keccak.Compute(abiHash);
            Deposit        deposit        = new Deposit(depositId, units, expiryTime, value);
            DepositDetails depositDetails = new DepositDetails(deposit, dataAsset, address, pepper, now,
                                                               Enumerable.Empty <TransactionInfo>(), 0, requiredConfirmations: _requiredBlockConfirmations);
            UInt256 gasPriceValue = gasPrice is null || gasPrice.Value == 0
                ? await _gasPriceService.GetCurrentAsync()
                : gasPrice.Value;

            await _depositRepository.AddAsync(depositDetails);

            Keccak?transactionHash = null;

            if (_logger.IsInfo)
            {
                _logger.Info($"Created a deposit with id: '{depositId}', for data asset: '{assetId}', address: '{address}'.");
            }
            if (_disableSendingDepositTransaction)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn("*** NDM sending deposit transaction is disabled ***");
                }
            }
            else
            {
                transactionHash = await _depositService.MakeDepositAsync(address, deposit, gasPriceValue);
            }

            if (transactionHash == null)
            {
                if (_logger.IsWarn)
                {
                    _logger.Warn($"Failed to make a deposit with for data asset: '{assetId}', address: '{address}', gas price: {gasPriceValue} wei.");
                }
                return(null);
            }

            if (_logger.IsInfo)
            {
                _logger.Info($"Sent a deposit with id: '{depositId}', transaction hash: '{transactionHash}' for data asset: '{assetId}', address: '{address}', gas price: {gasPriceValue} wei.");
            }

            depositDetails.AddTransaction(TransactionInfo.Default(transactionHash, deposit.Value, gasPriceValue,
                                                                  _depositService.GasLimit, now));
            await _depositRepository.UpdateAsync(depositDetails);

            return(depositId);
        }
예제 #9
0
 private static DepositDetails GetDepositDetails(uint timestamp = 0,
                                                 IEnumerable <TransactionInfo> transactions = null)
 => new DepositDetails(new Deposit(Keccak.Zero, 1, 1, 1),
                       GetDataAsset(DataAssetUnitType.Unit), TestItem.AddressB, Array.Empty <byte>(), 1,
                       transactions ?? new[] { TransactionInfo.Default(TestItem.KeccakA, 1, 1, 1, 1) }, timestamp);
 private static DepositDetails GetDepositDetails(uint confirmationTimestamp = 0, uint expiryTime = 1,
                                                 bool kycRequired           = false)
 => new DepositDetails(new Deposit(Keccak.Zero, 1, expiryTime, 1),
                       GetDataAsset(kycRequired), TestItem.AddressB, Array.Empty <byte>(), 1,
                       new [] { TransactionInfo.Default(TestItem.KeccakA, 1, 1, 1, 1) }, confirmationTimestamp);
예제 #11
0
 private static DepositDetails GetDepositDetails(uint timestamp = 0)
 => new DepositDetails(new Deposit(TestItem.KeccakA, 1, 1, 1),
                       GetDataAsset(DataAssetUnitType.Unit), TestItem.AddressA, Array.Empty <byte>(), 1,
                       new [] { TransactionInfo.Default(TestItem.KeccakA, 1, 1, 1, 1) }, timestamp);