Deploy contracts to deterministic addresses using CREATE2 with Nethereum (.NET). Use this skill whenever the user asks about CREATE2, deterministic deployment, counterfactual addresses, predictable contract addresses, cross-chain same-address deployment, deployment proxies, or address prediction in C#/.NET.
CREATE2 lets you deploy a contract to a predictable address that depends only on the deployer, a salt, and the bytecode. This is useful for counterfactual deployments (predicting addresses before deployment), deploying the same contract to the same address across multiple chains, and factory patterns like Account Abstraction.
NuGet: Nethereum.Web3
dotnet add package Nethereum.Web3
The service is accessible via web3.Eth.Create2DeterministicDeploymentProxyService.
The CREATE2 address formula is:
address = keccak256(0xff ++ deployerAddress ++ salt ++ keccak256(bytecode))[12:]
Because the address depends only on these inputs, you can compute it before deployment — and anyone with the same inputs gets the same result.
Calculate the address without deploying. This is a pure local computation — no transaction, no gas:
var create2Service = web3.Eth.Create2DeterministicDeploymentProxyService;
var salt = "0x0000000000000000000000000000000000000000000000000000000000000001";
var predictedAddress = create2Service
.CalculateCreate2Address<MyContractDeployment>(
new MyContractDeployment { /* constructor args */ },
proxyAddress,
salt);
Before deploying, verify the contract doesn't already exist at the predicted address. This avoids wasting gas on a transaction that will fail:
var alreadyDeployed = await create2Service
.HasContractAlreadyDeployedAsync(predictedAddress);
The deployment goes through a deterministic proxy contract. The proxy forwards the bytecode + salt to the CREATE2 opcode:
var salt = "0x0000000000000000000000000000000000000000000000000000000000000001";
var result = await create2Service
.DeployContractRequestAndWaitForReceiptAsync<MyContractDeployment>(
new MyContractDeployment { /* constructor args */ },
proxyAddress,
salt);
Console.WriteLine($"Deployed to: {result.ContractAddress}");
The result's ContractAddress will match the predicted address exactly.
If the deterministic deployment proxy isn't deployed on your chain yet (common on private/app chains), deploy it first:
var proxyAddress = await create2Service
.DeployProxyAndGetContractAddressAsync();
On public networks (Mainnet, Sepolia, Polygon, etc.), the standard proxy is usually already deployed.
var proxyDeployed = await create2Service
.HasProxyBeenDeployedAsync(proxyAddress);
For deployments that include the chain ID (producing a different proxy address per chain, but deterministic on each):
var deployment = await create2Service
.GenerateEIP155DeterministicDeploymentAsync();
| Task | Method |
|---|---|
| Predict address | CalculateCreate2Address<T>(deployment, proxy, salt) |
| Check if deployed | HasContractAlreadyDeployedAsync(address) |
| Deploy contract | DeployContractRequestAndWaitForReceiptAsync<T>(deployment, proxy, salt) |
| Deploy proxy | DeployProxyAndGetContractAddressAsync() |
| Check proxy | HasProxyBeenDeployedAsync(proxyAddress) |
For full documentation, see: https://docs.nethereum.com/docs/smart-contracts/guide-create2-deployment