Skip to content

Commit

Permalink
Deterministic deployment with custom signer to work across multiple c…
Browse files Browse the repository at this point in the history
…hains
  • Loading branch information
juanfranblanco committed May 1, 2024
1 parent 9089c74 commit 4b4fc61
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ namespace Nethereum.Contracts.Create2Deployment
{

/// <summary>
/// Deterministic Deployment Proxy Deployment raw transaction, gas price, signer address, address, based on https://github.com/Arachnid/deterministic-deployment-proxy.git
/// Deterministic Deployment Proxy Deployment support https://github.com/Arachnid/deterministic-deployment-proxy.git and extended to support EIP155
///
/// Use in combination with the Create2DeterministicDeploymentProxyService to create EIP155 create2 deployments
///
/// The default values are created using the deterministic-deployment-proxy tool
Expand All @@ -26,15 +27,16 @@ namespace Nethereum.Contracts.Create2Deployment
/// npm run build
/// you can find the raw transaction and the bytecode in the output folder
///
/// EIP155 support is added by using the ChainId to calculate the V value and Legacy transaction signing
/// </summary>

public class Create2DeterministicDeploymentProxyDeployment
{
public const string DefaultRawTransaction = "f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222";
public const string DefaultSignerAddress = "3fab184622dc19b6109349b94811493bf2a45362";
public const string DefaultAddress = "4e59b44847b379578588920ca78fbf26c0b4956c";
public static readonly long DefaultGasPrice = 100000000000;
public static readonly long DefaultGasLimit = 100000;
public const long DefaultGasPrice = 100000000000;
public const long DefaultGasLimit = 100000;
public static readonly byte DefaultV = 21;
public static int DefaultRecId = 1;
public static BigInteger CalculateVForChainId(BigInteger chainId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Nethereum.Contracts.Create2Deployment
///
/// Use in combination with the Create2DeterministicDeployment object to create EIP155 create2 deployments or the default legacy deployments
///
/// EIP155 support is added by using the ChainId to calculate the V value and Legacy transaction signing
/// EIP155 support is added by using the ChainId to calculate the V value and Legacy transaction signing, note this will not provide the same address for all chains as per the legacy deployment
/// </summary>
public class Create2DeterministicDeploymentProxyService
{
Expand All @@ -35,14 +35,71 @@ public async Task<bool> HasProxyBeenDeployedAsync(string address)

}

public async Task<Create2DeterministicDeploymentProxyDeployment> GenerateEIP155Create2DeterministicDeploymentProxyDeploymentForCurrentChainAsync()
/// <summary>
/// Create a deterministic deployment EIP155 using the predefined Create2DeterministicDeploymentProxyDeployment ByteCode and the current Account and chainId
/// configured in Web3 as the signer
/// </summary>
public async Task<Create2DeterministicDeploymentProxyDeployment> GenerateEIP155DeterministicDeploymentAsync
(
long gasPrice = Create2DeterministicDeploymentProxyDeployment.DefaultGasPrice,
long gasLimit = Create2DeterministicDeploymentProxyDeployment.DefaultGasLimit,
long nonce =0
)
{
var chainId = await _ethApiContractService.ChainId.SendRequestAsync();
return GenerateEIP155Create2DeterministicDeploymentProxyDeployment(chainId);
var chainId = _ethApiContractService.TransactionManager.ChainId;
if (chainId == null)
{
chainId = await _ethApiContractService.ChainId.SendRequestAsync();
}
var transactionInput = new TransactionInput()
{
From = _ethApiContractService.TransactionManager.Account.Address,
GasPrice = new HexBigInteger(gasPrice),
Gas = new HexBigInteger(gasLimit),
Data = Create2DeterministicDeploymentProxyDeployment.ByteCode,
Value = new HexBigInteger(0),
Nonce = new HexBigInteger(nonce)
};

var rawTransaction = await _ethApiContractService.TransactionManager.SignTransactionAsync(transactionInput);
var contractAddress = ContractUtils.CalculateContractAddress(transactionInput.From, (int)nonce);
return new Create2DeterministicDeploymentProxyDeployment()
{
GasLimit = gasLimit,
GasPrice = gasPrice,
RawTransaction = rawTransaction,
SignerAddress = transactionInput.From,
Address = contractAddress,
ChainId = chainId
};

}


public Create2DeterministicDeploymentProxyDeployment GenerateEIP155Create2DeterministicDeploymentProxyDeployment(BigInteger chainId)

/// <summary>
/// Create a deterministic deployment EIP155 for the current chain using the predefined Create2DeterministicDeploymentProxyDeployment ByteCode and recovery signature
/// </summary>
/// <remarks>
/// The proxy address and signer address will be different depending on the chain, use GenerateEIP155DeterministicDeploymentAsync with your own private key to get the same address for all chains
/// </remarks>
public async Task<Create2DeterministicDeploymentProxyDeployment> GenerateEIP155DeterministicDeploymentUsingPreconfiguredSignatureAsync()
{
var chainId = _ethApiContractService.TransactionManager.ChainId;
if(chainId == null)
{
chainId = await _ethApiContractService.ChainId.SendRequestAsync();
}
return GenerateEIP155DeterministicDeploymentUsingPreconfiguredSignatureAsync(chainId.Value);
}

/// <summary>
/// Create a deterministic deployment for a chain using the predefined Create2DeterministicDeploymentProxyDeployment ByteCode and recovery signature
/// </summary>
/// <remarks>
/// The proxy address and signer address will be different depending on the chain, use GenerateEIP155DeterministicDeploymentAsync with your own private key to get the same address for all chains
/// </remarks>
public Create2DeterministicDeploymentProxyDeployment GenerateEIP155DeterministicDeploymentUsingPreconfiguredSignatureAsync(BigInteger chainId)
{
var nonce = 0;
var legacyTransactionChainId = new LegacyTransactionChainId(
Expand Down
2 changes: 2 additions & 0 deletions src/Nethereum.RPC/TransactionManagers/ITransactionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public interface ITransactionManager
ITransactionReceiptService TransactionReceiptService { get; set; }
bool CalculateOrSetDefaultGasPriceFeesIfNotSet { get; set; }
bool EstimateOrSetDefaultGasIfNotSet { get; set; }
BigInteger? ChainId { get; }

Task<TransactionReceipt> SendTransactionAndWaitForReceiptAsync(TransactionInput transactionInput, CancellationToken cancellationToken = default);


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public Create2DeploymentTests(EthereumClientIntegrationFixture ethereumClientInt
public async Task ShouldDeployDeterministicDeployer()
{
var web3 = _ethereumClientIntegrationFixture.GetWeb3();
var deployment = await web3.Eth.Create2DeterministicDeploymentProxyService.GenerateEIP155Create2DeterministicDeploymentProxyDeploymentForCurrentChainAsync();
var deployment = await web3.Eth.Create2DeterministicDeploymentProxyService.GenerateEIP155DeterministicDeploymentUsingPreconfiguredSignatureAsync();
var existDeployer = await web3.Eth.Create2DeterministicDeploymentProxyService.HasProxyBeenDeployedAsync(deployment.Address);
if(!existDeployer)
{
Expand All @@ -38,14 +38,45 @@ public async Task ShouldDeployDeterministicDeployer()
}
}

[Fact]
public async Task ShouldDeployDeterministicDeployerUsingACustomSigner()
{
var privateKeyCustomSigner = "541dbf545002f8832bcabbe05dd5dd86ee11a3f21ea6711b2ed192afc103fa41";
var accountSignerDeployerCurrentChain = new Nethereum.Web3.Accounts.Account(privateKeyCustomSigner, EthereumClientIntegrationFixture.ChainId);
var web3SignerDeployerCurrentChain = new Web3.Web3(accountSignerDeployerCurrentChain);
var deploymentProxyCurrentChain = await web3SignerDeployerCurrentChain.Eth.Create2DeterministicDeploymentProxyService.GenerateEIP155DeterministicDeploymentAsync();

var accountSignerDeployerDifferentChain = new Nethereum.Web3.Accounts.Account(privateKeyCustomSigner, 1);
var web3SignerDeployerDifferentChain = new Web3.Web3(accountSignerDeployerDifferentChain);
var deploymentProxyDifferentChain = await web3SignerDeployerDifferentChain.Eth.Create2DeterministicDeploymentProxyService.GenerateEIP155DeterministicDeploymentAsync();

Assert.True(deploymentProxyCurrentChain.Address.IsTheSameAddress(deploymentProxyDifferentChain.Address));
Assert.True(deploymentProxyCurrentChain.SignerAddress.IsTheSameAddress(deploymentProxyDifferentChain.SignerAddress));

var web3 = _ethereumClientIntegrationFixture.GetWeb3();

var existDeployer = await web3.Eth.Create2DeterministicDeploymentProxyService.HasProxyBeenDeployedAsync(deploymentProxyCurrentChain.Address);
if (!existDeployer)
{
var addressDeployer = await web3.Eth.Create2DeterministicDeploymentProxyService.DeployProxyAndGetContractAddressAsync(deploymentProxyCurrentChain);
Assert.True(addressDeployer.IsTheSameAddress(deploymentProxyCurrentChain.Address));

var existDeployerAfter = await web3.Eth.Create2DeterministicDeploymentProxyService.HasProxyBeenDeployedAsync(deploymentProxyCurrentChain.Address);
Assert.True(existDeployerAfter);
}
}



[Fact]
public async Task ShouldDeployCreate2UsingDeterministicDeployer()
{
var web3 = _ethereumClientIntegrationFixture.GetWeb3();
//var web3 = new Web3.Web3(new Nethereum.Web3.Accounts.Account(EthereumClientIntegrationFixture.AccountPrivateKey));
var salt = "0x1234567890123456789012345678901234567890123456789012345678901234";
var create2DeterministicDeploymentProxyService = web3.Eth.Create2DeterministicDeploymentProxyService;

var deployment = await create2DeterministicDeploymentProxyService.GenerateEIP155Create2DeterministicDeploymentProxyDeploymentForCurrentChainAsync();
var deployment = await create2DeterministicDeploymentProxyService.GenerateEIP155DeterministicDeploymentUsingPreconfiguredSignatureAsync();
var addressDeployer = await create2DeterministicDeploymentProxyService.DeployProxyAndGetContractAddressAsync(deployment);

var contractByteCode =
Expand Down

0 comments on commit 4b4fc61

Please sign in to comment.