236 lines
9.2 KiB
C#
Raw Normal View History

using System.Numerics;
using BlockchainUtils;
using Logging;
2023-12-19 15:30:46 +01:00
using Nethereum.ABI.FunctionEncoding.Attributes;
2023-04-18 13:22:41 +02:00
using Nethereum.Contracts;
using Nethereum.Model;
using Nethereum.RPC.Eth.Blocks;
2023-09-19 11:51:59 +02:00
using Nethereum.RPC.Eth.DTOs;
2023-04-14 10:51:35 +02:00
using Nethereum.Web3;
using Utils;
namespace NethereumWorkflow
{
2023-04-14 12:37:05 +02:00
public class NethereumInteraction
2023-04-14 10:51:35 +02:00
{
private readonly BlockCache blockCache;
2024-03-21 16:26:48 +01:00
2023-09-15 16:27:08 +02:00
private readonly ILog log;
2023-04-14 10:51:35 +02:00
private readonly Web3 web3;
internal NethereumInteraction(ILog log, Web3 web3, BlockCache blockCache)
2023-04-14 10:51:35 +02:00
{
2023-04-25 11:31:15 +02:00
this.log = log;
2023-04-14 10:51:35 +02:00
this.web3 = web3;
this.blockCache = blockCache;
2023-04-14 10:51:35 +02:00
}
public string SendEth(string toAddress, Ether eth)
{
var asDecimal = ((decimal)eth.Wei) / (decimal)TokensIntExtensions.WeiPerEth;
return SendEth(toAddress, asDecimal);
}
public string SendEth(string toAddress, decimal ethAmount)
2023-09-19 11:51:59 +02:00
{
return DebugLogWrap(() =>
{
var receipt = Time.Wait(web3.Eth.GetEtherTransferService().TransferEtherAndWaitForReceiptAsync(toAddress, ethAmount));
if (!receipt.Succeeded()) throw new Exception("Unable to send Eth");
return receipt.TransactionHash;
}, nameof(SendEth));
2023-09-19 11:51:59 +02:00
}
public BigInteger GetEthBalance()
2023-09-19 11:51:59 +02:00
{
return DebugLogWrap(() =>
{
return GetEthBalance(web3.TransactionManager.Account.Address);
}, nameof(GetEthBalance));
2023-09-19 11:51:59 +02:00
}
public BigInteger GetEthBalance(string address)
2023-09-19 11:51:59 +02:00
{
return DebugLogWrap(() =>
{
var balance = Time.Wait(web3.Eth.GetBalance.SendRequestAsync(address));
return balance.Value;
}, nameof(GetEthBalance));
2023-09-19 11:51:59 +02:00
}
2023-09-19 13:39:24 +02:00
public TResult Call<TFunction, TResult>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new()
2023-04-18 13:22:41 +02:00
{
return DebugLogWrap(() =>
{
var handler = web3.Eth.GetContractQueryHandler<TFunction>();
return Time.Wait(handler.QueryAsync<TResult>(contractAddress, function));
}, nameof(Call) + "." + typeof(TFunction).ToString());
}
public TResult Call<TFunction, TResult>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new()
{
return DebugLogWrap(() =>
{
var handler = web3.Eth.GetContractQueryHandler<TFunction>();
return Time.Wait(handler.QueryAsync<TResult>(contractAddress, function, new BlockParameter(blockNumber)));
}, nameof(Call) + "." + typeof(TFunction).ToString());
}
public void Call<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new()
{
DebugLogWrap<string>(() =>
{
var handler = web3.Eth.GetContractQueryHandler<TFunction>();
Time.Wait(handler.QueryRawAsync(contractAddress, function));
return string.Empty;
}, nameof(Call) + "." + typeof(TFunction).ToString());
}
public void Call<TFunction>(string contractAddress, TFunction function, ulong blockNumber) where TFunction : FunctionMessage, new()
{
DebugLogWrap<string>(() =>
{
var handler = web3.Eth.GetContractQueryHandler<TFunction>();
var result = Time.Wait(handler.QueryRawAsync(contractAddress, function, new BlockParameter(blockNumber)));
return string.Empty;
}, nameof(Call) + "." + typeof(TFunction).ToString());
}
2023-12-15 11:02:06 +01:00
public string SendTransaction<TFunction>(string contractAddress, TFunction function) where TFunction : FunctionMessage, new()
{
return DebugLogWrap(() =>
{
var handler = web3.Eth.GetContractTransactionHandler<TFunction>();
var receipt = Time.Wait(handler.SendRequestAndWaitForReceiptAsync(contractAddress, function));
if (!receipt.Succeeded()) throw new Exception("Unable to perform contract transaction.");
return receipt.TransactionHash;
}, nameof(SendTransaction) + "." + typeof(TFunction).ToString());
}
public Transaction GetTransaction(string transactionHash)
{
return DebugLogWrap(() =>
{
return Time.Wait(web3.Eth.Transactions.GetTransactionByHash.SendRequestAsync(transactionHash));
}, nameof(GetTransaction));
}
2023-09-19 13:58:45 +02:00
public decimal? GetSyncedBlockNumber()
{
return DebugLogWrap<decimal?>(() =>
{
var sync = Time.Wait(web3.Eth.Syncing.SendRequestAsync());
var number = Time.Wait(web3.Eth.Blocks.GetBlockNumber.SendRequestAsync());
var numberOfBlocks = number.ToDecimal();
if (sync.IsSyncing) return null;
return numberOfBlocks;
}, nameof(GetTransaction));
2023-09-19 13:58:45 +02:00
}
2023-09-19 13:39:24 +02:00
2023-09-19 13:58:45 +02:00
public bool IsContractAvailable(string abi, string contractAddress)
{
return DebugLogWrap(() =>
2023-09-19 13:58:45 +02:00
{
try
{
var contract = web3.Eth.GetContract(abi, contractAddress);
return contract != null;
}
catch
{
return false;
}
}, nameof(IsContractAvailable));
2023-09-19 13:58:45 +02:00
}
2023-12-19 15:30:46 +01:00
2024-03-27 15:39:42 +01:00
public List<EventLog<TEvent>> GetEvents<TEvent>(string address, BlockInterval blockRange) where TEvent : IEventDTO, new()
2023-12-19 15:30:46 +01:00
{
return DebugLogWrap(() =>
{
return GetEvents<TEvent>(address, blockRange.From, blockRange.To);
}, nameof(GetEvents) + "." + typeof(TEvent).ToString());
2023-12-19 15:30:46 +01:00
}
2023-12-19 15:43:26 +01:00
public List<EventLog<TEvent>> GetEvents<TEvent>(string address, ulong fromBlockNumber, ulong toBlockNumber) where TEvent : IEventDTO, new()
2023-12-19 15:30:46 +01:00
{
return DebugLogWrap(() =>
{
var logs = new List<FilterLog>();
var p = web3.Processing.Logs.CreateProcessor(
action: logs.Add,
minimumBlockConfirmations: 1,
criteria: l => l.IsLogForEvent<TEvent>()
);
2025-06-26 14:10:57 +02:00
var from = new BlockParameter(fromBlockNumber);
var to = new BlockParameter(toBlockNumber);
var ct = new CancellationTokenSource().Token;
Time.Wait(p.ExecuteAsync(toBlockNumber: to.BlockNumber, cancellationToken: ct, startAtBlockNumberIfNotProcessed: from.BlockNumber));
2025-06-26 14:10:57 +02:00
return logs
.Where(l => l.IsLogForEvent<TEvent>())
.Select(l => l.DecodeEvent<TEvent>())
.ToList();
}, nameof(GetEvents) + "." + typeof(TEvent).ToString());
2023-12-19 15:30:46 +01:00
}
2024-03-27 15:39:42 +01:00
public BlockInterval ConvertTimeRangeToBlockRange(TimeRange timeRange)
{
return DebugLogWrap(() =>
{
if (timeRange.To - timeRange.From < TimeSpan.FromSeconds(1.0))
throw new Exception(nameof(ConvertTimeRangeToBlockRange) + ": Time range too small.");
2025-07-10 13:24:49 +02:00
var wrapper = new Web3Wrapper(web3, log);
var blockTimeFinder = new BlockTimeFinder(blockCache, wrapper, log);
2024-03-27 15:39:42 +01:00
var fromBlock = blockTimeFinder.GetLowestBlockNumberAfter(timeRange.From);
var toBlock = blockTimeFinder.GetHighestBlockNumberBefore(timeRange.To);
2024-03-27 15:39:42 +01:00
if (fromBlock == null || toBlock == null)
{
throw new Exception("Failed to convert time range to block range.");
}
2024-03-27 15:39:42 +01:00
return new BlockInterval(
timeRange: timeRange,
from: fromBlock.Value,
to: toBlock.Value
);
}, nameof(ConvertTimeRangeToBlockRange));
2024-03-27 15:39:42 +01:00
}
2024-04-13 09:19:20 +02:00
public BlockTimeEntry GetBlockForNumber(ulong number)
{
return DebugLogWrap(() =>
{
var wrapper = new Web3Wrapper(web3, log);
var blockTimeFinder = new BlockTimeFinder(blockCache, wrapper, log);
return blockTimeFinder.Get(number);
}, nameof(GetBlockForNumber));
2024-04-13 09:19:20 +02:00
}
2025-05-04 11:20:33 +02:00
public BlockWithTransactions GetBlockWithTransactions(ulong number)
2025-05-04 11:20:33 +02:00
{
return DebugLogWrap(() =>
{
var retry = new Retry(nameof(GetBlockWithTransactions),
maxTimeout: TimeSpan.FromMinutes(1.0),
sleepAfterFail: TimeSpan.FromSeconds(1.0),
onFail: f => { },
failFast: false);
2025-05-22 13:55:03 +02:00
return retry.Run(() => Time.Wait(web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(new BlockParameter(number))));
}, nameof(GetBlockWithTransactions));
}
private T DebugLogWrap<T>(Func<T> task, string name = "")
{
log.Debug($"{name} start...", 1);
var result = task();
log.Debug($"{name} finished", 1);
return result;
2025-05-04 11:20:33 +02:00
}
}
2023-04-14 10:51:35 +02:00
}