public async Task <Keccak?> ClaimEarlyRefundAsync(Address onBehalfOf, EarlyRefundClaim earlyRefundClaim, UInt256 gasPrice) { byte[] txData = _abiEncoder.Encode(AbiEncodingStyle.IncludeSignature, ContractData.ClaimEarlyRefundSig, earlyRefundClaim.AssetId.Bytes, earlyRefundClaim.Units, earlyRefundClaim.Value, earlyRefundClaim.ExpiryTime, earlyRefundClaim.Pepper, earlyRefundClaim.Provider, earlyRefundClaim.ClaimableAfter, earlyRefundClaim.Signature.V, earlyRefundClaim.Signature.R, earlyRefundClaim.Signature.S, onBehalfOf); Transaction transaction = new Transaction(); transaction.Value = 0; transaction.Data = txData; transaction.To = _contractAddress; transaction.SenderAddress = onBehalfOf; transaction.GasLimit = (long)GasLimit; transaction.GasPrice = gasPrice; transaction.Nonce = await _blockchainBridge.GetNonceAsync(onBehalfOf); _wallet.Sign(transaction, await _blockchainBridge.GetNetworkIdAsync()); if (_logger.IsInfo) { _logger.Info($"Sending an early refund claim transaction on {earlyRefundClaim.DepositId} to be refunded to {earlyRefundClaim.RefundTo}"); } return(await _blockchainBridge.SendOwnTransactionAsync(transaction)); }
public async Task TryClaimEarlyRefundAsync(DepositDetails deposit, Address refundTo) { var now = (ulong)_blockchainBridge.Head.Timestamp; if (!deposit.CanClaimEarlyRefund(now)) { return; } var depositId = deposit.Deposit.Id; var transactionHash = deposit.ClaimedRefundTransactionHash; if (transactionHash is null) { var provider = deposit.DataAsset.Provider.Address; var ticket = deposit.EarlyRefundTicket; var 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); transactionHash = _refundService.ClaimEarlyRefund(refundTo, earlyRefundClaim); deposit.SetClaimedRefundTransactionHash(transactionHash); await _depositRepository.UpdateAsync(deposit); if (_logger.IsInfo) { _logger.Info($"Claimed an early refund for deposit: '{depositId}', transaction hash: '{transactionHash}' (awaits a confirmation)."); } } await TryConfirmClaimAsync(deposit, "early "); }
public async Task <RefundClaimStatus> TryClaimEarlyRefundAsync(DepositDetails deposit, Address refundTo) { var now = _timestamper.EpochSeconds; if (!deposit.CanClaimEarlyRefund(now)) { return(RefundClaimStatus.Empty); } var latestBlock = await _blockchainBridge.GetLatestBlockAsync(); now = (ulong)latestBlock.Timestamp; if (!deposit.CanClaimEarlyRefund(now)) { return(RefundClaimStatus.Empty); } var depositId = deposit.Deposit.Id; var transactionHash = deposit.ClaimedRefundTransaction?.Hash; if (transactionHash is null) { var provider = deposit.DataAsset.Provider.Address; var ticket = deposit.EarlyRefundTicket; var 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); var gasPrice = await _gasPriceService.GetCurrentAsync(); 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.SetClaimedRefundTransaction(new TransactionInfo(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)."); } } var confirmed = await TryConfirmClaimAsync(deposit, "early "); return(confirmed ? RefundClaimStatus.Confirmed(transactionHash) : RefundClaimStatus.Unconfirmed(transactionHash)); }
public Keccak ClaimEarlyRefund(Address onBehalfOf, EarlyRefundClaim earlyRefundClaim) { byte[] txData = _abiEncoder.Encode(AbiEncodingStyle.IncludeSignature, ContractData.ClaimEarlyRefundSig, earlyRefundClaim.AssetId.Bytes, earlyRefundClaim.Units, earlyRefundClaim.Value, earlyRefundClaim.ExpiryTime, earlyRefundClaim.Pepper, earlyRefundClaim.Provider, earlyRefundClaim.ClaimableAfter, earlyRefundClaim.Signature.V, earlyRefundClaim.Signature.R, earlyRefundClaim.Signature.S, onBehalfOf); Transaction transaction = new Transaction(); transaction.Value = 0; transaction.Data = txData; transaction.To = _contractAddress; transaction.SenderAddress = onBehalfOf; transaction.GasLimit = 90000; // check transaction.GasPrice = 20.GWei(); transaction.Nonce = _txPool.ReserveOwnTransactionNonce(onBehalfOf); if (_logger.IsInfo) { _logger.Info($"Sending an early refund claim transaction on {earlyRefundClaim.DepositId} to be refunded to {earlyRefundClaim.RefundTo}"); } _wallet.Sign(transaction, _blockchainBridge.GetNetworkId()); return(_blockchainBridge.SendTransaction(transaction, true)); }
public async Task Can_claim_early_refund() { uint timestamp = 1546871954; _bridge.NextBlockPlease(timestamp); DepositService depositService = new DepositService(_ndmBridge, _abiEncoder, _wallet, _contractAddress); Keccak assetId = Keccak.Compute("data asset"); uint expiryTime = timestamp + (uint)TimeSpan.FromDays(4).TotalSeconds; UInt256 value = 1.Ether(); uint units = 10U; byte[] pepper = new byte[16]; AbiSignature depositAbiDef = new AbiSignature("deposit", new AbiBytes(32), new AbiUInt(32), new AbiUInt(96), new AbiUInt(32), new AbiBytes(16), AbiType.Address, AbiType.Address); byte[] depositData = _abiEncoder.Encode(AbiEncodingStyle.Packed, depositAbiDef, assetId.Bytes, units, value, expiryTime, pepper, _providerAccount, _consumerAccount); Keccak depositId = Keccak.Compute(depositData); Deposit deposit = new Deposit(depositId, units, expiryTime, value); Keccak depositTxHash = await depositService.MakeDepositAsync(_consumerAccount, deposit, 20.GWei()); _bridge.IncrementNonce(_consumerAccount); TxReceipt depositTxReceipt = _bridge.GetReceipt(depositTxHash); TestContext.WriteLine("GAS USED FOR DEPOSIT: {0}", depositTxReceipt.GasUsed); Assert.AreEqual(StatusCode.Success, depositTxReceipt.StatusCode, $"deposit made {depositTxReceipt.Error} {Encoding.UTF8.GetString(depositTxReceipt.ReturnValue ?? new byte[0])}"); // calls revert and cannot reuse the same state - use only for manual debugging // Assert.True(depositService.VerifyDeposit(deposit.Id), "deposit verified"); uint claimableAfter = timestamp + (uint)TimeSpan.FromDays(1).TotalSeconds; AbiSignature earlyRefundAbiDef = new AbiSignature("earlyRefund", new AbiBytes(32), new AbiUInt(32)); byte[] earlyRefundData = _abiEncoder.Encode(AbiEncodingStyle.Packed, earlyRefundAbiDef, depositId.Bytes, claimableAfter); RefundService refundService = new RefundService(_ndmBridge, _abiEncoder, _depositRepository, _contractAddress, LimboLogs.Instance); // it will not work so far as we do everything within the same block and timestamp is wrong uint newTimestamp = 1546871954 + (uint)TimeSpan.FromDays(2).TotalSeconds; _bridge.NextBlockPlease(newTimestamp); Signature earlySig = _wallet.Sign(Keccak.Compute(earlyRefundData), _providerAccount); EarlyRefundClaim earlyRefundClaim = new EarlyRefundClaim(depositId, assetId, units, value, expiryTime, pepper, _providerAccount, claimableAfter, earlySig, _consumerAccount); UInt256 balanceBefore = _state.GetBalance(_consumerAccount); Keccak refundTxHash = await refundService.ClaimEarlyRefundAsync(_consumerAccount, earlyRefundClaim, 20.GWei()); TxReceipt refundReceipt = _bridge.GetReceipt(refundTxHash); TestContext.WriteLine("GAS USED FOR EARLY REFUND CLAIM: {0}", refundReceipt.GasUsed); Assert.AreEqual(StatusCode.Success, refundReceipt.StatusCode, $"early refund claim {refundReceipt.Error} {Encoding.UTF8.GetString(refundReceipt.ReturnValue ?? new byte[0])}"); UInt256 balanceAfter = _state.GetBalance(_consumerAccount); Assert.Greater(balanceAfter, balanceBefore); }
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)); }