Nethereum is the primary .NET library for talking to Polygon. Because Polygon PoS is EVM-equivalent, the same Nethereum APIs you would use against any Ethereum node work unchanged when you point them at https://polygon.therpc.io/YOUR_API_KEY. It targets .NET Standard 2.0+, so the same code runs on .NET Core, .NET 5/6/7+, and the older .NET Framework, and it is compatible with Unity3D, Xamarin, ASP.NET Core, and Blazor. Add it to your project with dotnet add package Nethereum.Web3.
Nethereum targets .NET Standard 2.0+ and is compatible with Unity3D, Xamarin, ASP.NET Core, and Blazor, so a single Polygon integration can be shared across a game client, a mobile app, and a web backend. Install it from NuGet with dotnet add package Nethereum.Web3.
Nethereum
To connect, instantiate new Web3(url) with your Polygon endpoint URL — https://polygon.therpc.io/YOUR_API_KEY — and reuse that single instance across your service. Every IO method in Nethereum returns an async Task, so always await them. Avoid blocking on .Result or .Wait(): in ASP.NET and Unity contexts that can deadlock the synchronization context and freeze your app.
using Nethereum.Web3;
using Nethereum.Web3.Accounts;
using Nethereum.Util;
using Nethereum.Hex.HexTypes;
public class EthereumService
{
private readonly Web3 _web3;
public EthereumService(string url)
{
_web3= new Web3(url);
}
public async Task<decimal> GetBalanceAsync(string address)
{
var balance = await _web3.Eth.GetBalance.SendRequestAsync(address);
return Web3.Convert.FromWei(balance.Value);
}
public async Task<string> SendTransactionAsync(
string privateKey,
string toAddress,
decimal etherAmount)
{
var account = new Account(privateKey);
var web3= new Web3(account, _web3.Client.Url);
var transaction = await web3.Eth.GetEtherTransferService()
Key features: full Polygon PoS integration over standard JSON-RPC, smart contract deployment and interaction, HD wallet support, Unity3D and Xamarin bindings for games and mobile, and IPC / RPC / WebSocket transports
Smart Contract Integration
To work with a deployed Polygon contract, get a handle from _web3.Eth.GetContract(abi, contractAddress), passing the contract's ABI JSON and its address on chain 137. From there, GetFunction(name) resolves a callable function: use CallAsync<T>(...) for read-only views, which cost no MATIC, and SendTransactionAsync(...) for state-changing writes, which submit a signed transaction and consume gas.
public class SmartContractService
{
private readonly Web3 _web3;
private readonly Contract _contract;
public SmartContractService(string url, string contractAddress, string abi)
In an ASP.NET Core app, register EthereumService in the dependency injection container in Program.cs (or Startup.cs) — typically as a singleton so the single Polygon Web3 connection is reused across requests — and let the framework inject it into your controllers. Inside each action, wrap the async call in a try/catch so a failed RPC request to the Polygon endpoint returns BadRequest with the error message instead of bubbling up as an unhandled 500.
public EthereumController(EthereumService ethereumService)
{
_ethereumService = ethereumService;
}
[HttpGet("balance/{address}")]
public async Task<ActionResult<decimal>> GetBalance(string address)
{
try
{
var balance = await _ethereumService.GetBalanceAsync(address);
return Ok(balance);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
Event Handling
To watch contract events on Polygon, define an event DTO matching your Solidity event, then use GetEvent<TEventDTO>(contractAddress) together with CreateFilterInput() to build a log filter. Polling that filter with GetFilterChanges returns the matching logs as they are mined, letting you react to on-chain activity such as token transfers without manually decoding raw log data.
public class EventMonitorService
{
private readonly Web3 _web3;
public async Task MonitorEventsAsync(string contractAddress, string eventName)
{
var filterAll = _web3.Eth.GetEvent<YourEventDTO>(contractAddress)
.CreateFilterInput();
var subscription = _web3.Eth.GetEvent<YourEventDTO>(contractAddress)
.GetFilterChanges(filterAll);
subscription.Subscribe(evt =>
{
Console.WriteLine($"New event: {evt.Event}");
});
}
}
Unity3D Integration
For a Unity3D game, initialize Web3 once in Start() or Awake() with the Polygon endpoint https://polygon.therpc.io/YOUR_API_KEY, since Polygon's low fees make it a popular choice for on-chain game assets paid in MATIC. Use async void only for top-level lifecycle hooks like Start(); for everything else prefer Task-returning helper methods so exceptions can be caught and awaited cleanly, rather than scattering async void across MonoBehaviour callbacks where errors are easy to lose.
public class EthereumUnityManager : MonoBehaviour
{
private Web3 _web3;
private async void Start()
{
_web3= new Web3("https://polygon.therpc.io/YOUR_API_KEY");
await InitializeWalletAsync();
}
private async Task InitializeWalletAsync()
{
try
{
var balance = await _web3.Eth.GetBalance.SendRequestAsync("YOUR_ADDRESS");