A .NET 9 library that provides comprehensive utilities and services for working with blockchain technology, built on top of Nethereum. This library simplifies common blockchain operations including wallet management, balance queries, transactions, gas estimation, and token transfers.
- HD Wallet Management: Generate and restore hierarchical deterministic wallets
- Balance Services: Query native token and ERC20/ERC721 token balances
- Transaction Services: Send and track blockchain transactions
- Transaction Status: Detect the correct lifecycle state of a transaction (pending, confirmed, reverted, replaced, dropped)
- Gas Estimation: Estimate gas costs for various transaction types
- Transfer Services: Simplified token transfer operations (native, ERC20, ERC721)
- Block Services: Query blockchain block information
- Network Health: Check blockchain network and RPC endpoint health before sending transactions
- Web3 Provider: Easy Web3 instance creation with various configurations
- .NET SDK 9.0 or later
- Redis (if using distributed nonce features via Tricksfor.DistributedNonce)
Install the package via NuGet (when published):
dotnet add package Tricksfor.BlockChainToolsOr reference it directly in your project:
<PackageReference Include="Tricksfor.BlockChainTools" Version="9.0.0" />In your Program.cs or startup configuration:
using BlockChainTools;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
// Register all BlockChainTools services
services.AddBlockChainTools();
var serviceProvider = services.BuildServiceProvider();Important: You must register HttpClient in your DI container for GasService to work properly. The GasService requires an HttpClient instance to communicate with RPC endpoints for gas price queries.
Create Web3 instances for querying or transactions:
using BlockChainTools.Interfaces;
var web3Provider = serviceProvider.GetRequiredService<IWeb3ProviderService>();
// For read-only operations (queries, balance checks)
var web3ReadOnly = web3Provider.CreateWeb3("https://polygon-rpc.com");
// For transactions (requires private key)
var web3WithAccount = web3Provider.CreateWeb3(
privateKey: "0x...",
chain: Nethereum.Signer.Chain.Polygon,
rpcUrl: "https://polygon-rpc.com"
);Query native and token balances:
using BlockChainTools.Interfaces;
var balanceService = serviceProvider.GetRequiredService<IBalanceService>();
// Get native token balance (e.g., MATIC on Polygon)
var nativeBalance = await balanceService.GetBalanceOfAsync(
web3,
"0xYourAddress...",
cancellationToken
);
// Get ERC20 token balance (e.g., USDC)
var usdcBalance = await balanceService.GetErc20BalanceAsync(
web3,
"0xUSDCContractAddress...",
"0xYourAddress...",
cancellationToken
);
// Get ERC721 token balance (NFTs)
var nftBalance = await balanceService.GetErc721BalanceAsync(
web3,
"0xNFTContractAddress...",
"0xYourAddress...",
cancellationToken
);Generate and manage hierarchical deterministic wallets:
using BlockChainTools.Interfaces;
using NBitcoin;
var hdWalletService = serviceProvider.GetRequiredService<IHdWalletService>();
// Generate a new wallet
var wallet = hdWalletService.GenerateWallet(
seedPassword: "your-secure-password",
wordCount: WordCount.Twelve
);
// Restore wallet from mnemonic
var restoredWallet = hdWalletService.RestoreWallet(
words: new List<string> { "word1", "word2", /* ... */ },
seedPassword: "your-secure-password"
);
// Get account by index
var account = hdWalletService.GetAccount(wallet, index: 0);
// Get account for specific chain
var polygonAccount = hdWalletService.GetAccount(
wallet,
Nethereum.Signer.Chain.Polygon,
index: 0
);
// Get Web3 instance with account
var web3 = hdWalletService.GetWeb3(
wallet,
Nethereum.Signer.Chain.Polygon,
index: 0,
rpcUrl: "https://polygon-rpc.com"
);Estimate gas and query gas prices:
using BlockChainTools.Interfaces;
var gasService = serviceProvider.GetRequiredService<IGasService>();
// Get current gas price from RPC
var gasPrice = await gasService.GetGasPriceAsync(
rpcUrl: "https://polygon-rpc.com",
cancellationToken
);
// Estimate gas for native token transfer
var transferGas = await gasService.EstimateTransferGasAsync(
web3,
toAddress: "0xRecipient...",
value: 1.5m,
cancellationToken
);
// Estimate gas for ERC20 transfer
var erc20Gas = await gasService.EstimateErc20TransferGasAsync(
web3,
erc20ContractAddress: "0xUSDC...",
toAddress: "0xRecipient...",
value: BigInteger.Parse("1000000"), // 1 USDC (6 decimals)
cancellationToken
);
// Estimate gas for ERC721 (NFT) transfer
var nftGas = await gasService.EstimateErc721TransferGasAsync(
web3,
erc721ContractAddress: "0xNFT...",
toAddress: "0xRecipient...",
tokenId: 42,
cancellationToken
);
// Calculate total amount to transfer whole balance
var totalAmount = await gasService.CalculateTotalAmountToTransferWholeBalanceAsync(
web3,
fromAddress: "0xYourAddress...",
cancellationToken
);Send tokens and NFTs:
using BlockChainTools.Interfaces;
using Nethereum.RPC.Eth.DTOs;
var transferService = serviceProvider.GetRequiredService<ITransferService>();
// Transfer native token (e.g., MATIC)
var txInput = new TransactionInput
{
From = "0xYourAddress...",
To = "0xRecipient...",
Value = new Nethereum.Hex.HexTypes.HexBigInteger(
Nethereum.Web3.Web3.Convert.ToWei(1.5m)
)
};
var txHash = await transferService.TransferAsync(web3, txInput);
// Transfer ERC20 token
var erc20Transfer = new Nethereum.Contracts.Standards.ERC20.ContractDefinition.TransferFunction
{
To = "0xRecipient...",
AmountToSend = BigInteger.Parse("1000000") // 1 USDC (6 decimals)
};
var erc20TxHash = await transferService.TransferAsync(
web3,
"0xUSDCContract...",
erc20Transfer
);
// Transfer ERC721 token (NFT)
var nftTransfer = new Nethereum.Contracts.Standards.ERC721.ContractDefinition.TransferFromFunction
{
From = "0xYourAddress...",
To = "0xRecipient...",
TokenId = 42
};
var nftTxHash = await transferService.TransferAsync(
web3,
"0xNFTContract...",
nftTransfer
);
// Transfer and wait for receipt
var receipt = await transferService.TransferAndWaitForReceiptAsync(web3, txInput);Query transaction details:
using BlockChainTools.Interfaces;
var transactionService = serviceProvider.GetRequiredService<ITransactionService>();
var transaction = await transactionService.GetTransactionByHashAsync(
web3,
hash: "0xTransactionHash...",
cancellationToken
);Query blockchain information:
using BlockChainTools.Interfaces;
var blockService = serviceProvider.GetRequiredService<IBlockService>();
var latestBlock = await blockService.GetLastBlockAsync(web3, cancellationToken);Detect the lifecycle state of a transaction:
using BlockChainTools.Interfaces;
using BlockChainTools.DataTransferObjects;
var txStatusService = serviceProvider.GetRequiredService<ITransactionStatusService>();
// Check the state of a transaction by hash
var stateInfo = await txStatusService.GetTransactionStateAsync(
web3,
"0xTransactionHash...",
cancellationToken
);
// stateInfo.State can be:
// TransactionState.Pending – known to node but not mined
// TransactionState.ConfirmedSuccess – receipt exists, status == 1
// TransactionState.ConfirmedReverted– receipt exists, status == 0 (on-chain revert)
// TransactionState.Replaced – another tx with the same nonce was mined first
// TransactionState.StalePending – node no longer knows the tx (likely dropped)
switch (stateInfo.State)
{
case TransactionState.ConfirmedSuccess:
case TransactionState.ConfirmedReverted:
Console.WriteLine($"Mined in block {stateInfo.BlockNumber}");
Console.WriteLine($"Receipt status: {stateInfo.ReceiptStatus}"); // 1 or 0
Console.WriteLine($"Gas used: {stateInfo.Receipt!.GasUsed}"); // full receipt available
Console.WriteLine($"Nonce: {stateInfo.Nonce}, Value: {stateInfo.Value}, Gas limit: {stateInfo.Gas}");
break;
case TransactionState.Replaced:
// The sender's confirmed nonce has already passed this tx's nonce
Console.WriteLine($"Tx nonce {stateInfo.Nonce} was replaced; sender's confirmed nonce is now {stateInfo.ConfirmedNonce}");
Console.WriteLine($"Original value: {stateInfo.Value}, gas limit: {stateInfo.Gas}");
break;
case TransactionState.Pending:
Console.WriteLine($"Still pending – nonce {stateInfo.Nonce}, value {stateInfo.Value}, gas limit {stateInfo.Gas}");
break;
case TransactionState.StalePending:
Console.WriteLine("Transaction dropped from the mempool");
break;
}| Property | ConfirmedSuccess / ConfirmedReverted | Pending | Replaced | StalePending |
|---|---|---|---|---|
State |
✅ | ✅ | ✅ | ✅ |
TransactionHash |
✅ | ✅ | ✅ | ✅ |
Receipt |
✅ | — | — | — |
ReceiptStatus |
✅ | — | — | — |
BlockNumber |
✅ | — | — | — |
Nonce |
✅ | ✅ | ✅ | — |
Value |
✅ | ✅ | ✅ | — |
Gas |
✅ | ✅ | ✅ | — |
ConfirmedNonce |
— | — | ✅ | — |
Receipt, ReceiptStatus, and BlockNumber are only available when a receipt exists (confirmed states).
Nonce, Value, and Gas are populated whenever the node still holds the transaction object.
ConfirmedNonce is exclusively set for the Replaced state — it holds the sender's current on-chain nonce at the point replacement was detected.
All properties are null for states where the data source is unavailable.
Check blockchain network health before sending transactions:
using BlockChainTools.Interfaces;
using Nethereum.Signer;
var healthService = serviceProvider.GetRequiredService<INetworkHealthService>();
// Full health check with expected chain and freshness threshold
var health = await healthService.CheckNetworkHealthAsync(
web3,
expectedChain: Chain.Polygon,
maxBlockAgeSeconds: 120,
cancellationToken
);
if (!health.IsHealthy)
{
foreach (var issue in health.Issues)
Console.WriteLine($"Issue: {issue}");
}
// Quick check without chain ID validation
var quickHealth = await healthService.CheckNetworkHealthAsync(web3);CreateWeb3(string rpcUrl)- Create Web3 for read-only operationsCreateWeb3(string privateKey, Chain chain, string rpcUrl)- Create Web3 for transactions
GetBalanceOfAsync(Web3, string address)- Get native token balanceGetErc20BalanceAsync(Web3, string contractAddress, string address)- Get ERC20 balanceGetErc721BalanceAsync(Web3, string contractAddress, string address)- Get ERC721 balance
GenerateWallet(string seedPassword, WordCount)- Generate new HD walletRestoreWallet(List<string> words, string seedPassword)- Restore from mnemonicGetAccount(Wallet, int index)- Get account by indexGetAccount(Wallet, Chain, int index)- Get account for specific chainGetWeb3(Wallet, Chain, int index, string rpcUrl)- Get Web3 with account
Note: Requires HttpClient to be registered in DI container
GetGasPriceAsync(string rpcUrl)- Get current gas priceEstimateTransferGasAsync(Web3, string to, decimal value)- Estimate native transfer gasEstimateErc20TransferGasAsync(Web3, string contract, string to, BigInteger value)- Estimate ERC20 gasEstimateErc721TransferGasAsync(Web3, string contract, string to, int tokenId)- Estimate NFT gasSuggestFeeToTransferWholeBalanceAsync(Web3, string from)- Suggest fee for full balance transferCalculateTotalAmountToTransferWholeBalanceAsync(Web3, string from)- Calculate transferable amount
TransferAsync(Web3, TransactionInput)- Transfer native tokensTransferAsync(Web3, string contract, TransferFunction)- Transfer ERC20TransferAsync(Web3, string contract, TransferFromFunction)- Transfer ERC721TransferAndWaitForReceiptAsync(...)- Transfer and wait for confirmation
GetTransactionByHashAsync(Web3, string hash)- Get transaction details
GetTransactionStateAsync(Web3, string transactionHash)- Determine the lifecycle state of a transaction (Pending, ConfirmedSuccess, ConfirmedReverted, Replaced, StalePending)
GetLastBlockAsync(Web3)- Get latest block number
CheckNetworkHealthAsync(Web3, Chain? expectedChain, int maxBlockAgeSeconds)- Check network health (block freshness, gas price availability, chain ID match)
BlockChainTools/
├── src/
│ └── BlockChainTools/
│ ├── Configuration.cs # DI registration
│ ├── Services/ # Service implementations
│ │ ├── BalanceService.cs
│ │ ├── BlockService.cs
│ │ ├── GasService.cs
│ │ ├── HdWalletService.cs
│ │ ├── NetworkHealthService.cs
│ │ ├── TransactionService.cs
│ │ ├── TransactionStatusService.cs
│ │ ├── TransferService.cs
│ │ └── Web3ProviderService.cs
│ ├── Interfaces/ # Service contracts
│ └── DataTransferObjects/ # DTOs for external APIs
└── tests/
└── BlockChainTools.Tests/ # Unit tests
- Nethereum.Web3 (6.0.4) - Ethereum Web3 implementation
- Nethereum.Accounts (6.0.4) - Account management
- Nethereum.Signer (6.0.4) - Transaction signing
- Nethereum.HdWallet (6.0.4) - HD wallet support
- Microsoft.Extensions.DependencyInjection (10.0.5) - DI support
- Tricksfor.DistributedNonce (10.0.2) - Distributed nonce management
Run the unit tests:
dotnet test tests/BlockChainTools.Tests/BlockChainTools.Tests.csprojThe test suite uses:
- NUnit for test framework
- NSubstitute for mocking
- DotNet.Testcontainers for integration tests
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Submit a pull request
This project is licensed under the MIT License. See the LICENSE file for details.
For issues, questions, or contributions, please visit the GitHub repository.