![]() |
VOOZH | about |
dotnet add package Nethereum.GnosisSafe --version 6.1.0
NuGet\Install-Package Nethereum.GnosisSafe -Version 6.1.0
<PackageReference Include="Nethereum.GnosisSafe" Version="6.1.0" />
<PackageVersion Include="Nethereum.GnosisSafe" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Nethereum.GnosisSafe" />Project file
paket add Nethereum.GnosisSafe --version 6.1.0
#r "nuget: Nethereum.GnosisSafe, 6.1.0"
#:package Nethereum.GnosisSafe@6.1.0
#addin nuget:?package=Nethereum.GnosisSafe&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Nethereum.GnosisSafe&version=6.1.0Install as a Cake Tool
Nethereum service for interacting with Gnosis Safe (now Safe) multisig wallet contracts. Provides EIP-712 typed transaction signing, multi-signature transaction building, and seamless integration with any Nethereum contract service through custom account and contract handler implementations.
dotnet add package Nethereum.GnosisSafe
Main service for interacting with Gnosis Safe contracts (GnosisSafeService.cs:13-738).
Contract Functions:
Transaction Building:
// GnosisSafeService.cs:31-39
public async Task<ExecTransactionFunction> BuildTransactionAsync(
EncodeTransactionDataFunction transactionData,
BigInteger chainId,
bool estimateSafeTxGas = false, params string[] privateKeySigners)
{
var nonce = await NonceQueryAsync().ConfigureAwait(false);
transactionData.SafeNonce = nonce;
return BuildTransaction(transactionData, chainId, privateKeySigners);
}
Multi-Signature Transaction Building:
// GnosisSafeService.cs:63-82
public async Task<ExecTransactionFunction> BuildMultiSignatureTransactionAsync<TFunctionMessage>(
EncodeTransactionDataFunction transactionData,
TFunctionMessage functionMessage,
BigInteger chainId,
bool estimateSafeTxGas = false, params string[] privateKeySigners)
where TFunctionMessage : FunctionMessage, new()
{
var nonce = await NonceQueryAsync().ConfigureAwait(false);
if (estimateSafeTxGas)
{
var toContract = transactionData.To;
var estimateHandler = Web3.Eth.GetContractTransactionHandler<TFunctionMessage>();
functionMessage.FromAddress = this.ContractHandler.ContractAddress;
var gasEstimateSafe = await estimateHandler.EstimateGasAsync(toContract, functionMessage);
transactionData.SafeTxGas = gasEstimateSafe;
}
transactionData.Data = functionMessage.GetCallData();
transactionData.SafeNonce = nonce;
return BuildTransaction(transactionData, chainId, privateKeySigners);
}
MultiSend Support:
// GnosisSafeService.cs:41-50
public Task<ExecTransactionFunction> BuildMultiSendTransactionAsync(
EncodeTransactionDataFunction transactionData,
BigInteger chainId,
string privateKeySigner,
bool estimateSafeTxGas = false, params IMultiSendInput[] multiSendInputs)
{
transactionData.Operation = (int)ContractOperationType.DelegateCall;
var multiSendFunction = new MultiSendFunction(multiSendInputs);
return BuildMultiSignatureTransactionAsync(transactionData, multiSendFunction, chainId,
estimateSafeTxGas, privateKeySigner);
}
Type Definition Creation:
// GnosisSafeService.cs:147-159
public static TypedData<GnosisSafeEIP712Domain> GetGnosisSafeTypedDefinition(
BigInteger chainId, string verifyingContractAddress)
{
return new TypedData<GnosisSafeEIP712Domain>
{
Domain = new GnosisSafeEIP712Domain
{
ChainId = chainId,
VerifyingContract = verifyingContractAddress
},
Types = MemberDescriptionFactory.GetTypesMemberDescription(
typeof(GnosisSafeEIP712Domain), typeof(EncodeTransactionDataFunction)),
PrimaryType = "SafeTx",
};
}
Transaction Hash Computation:
// GnosisSafeService.cs:181-186
public static byte[] GetEncodedTransactionDataHash(
EncodeTransactionDataFunction transactionData,
BigInteger chainId,
string verifyingContractAddress)
{
var typedDefinition = GetGnosisSafeTypedDefinition(chainId, verifyingContractAddress);
return Eip712TypedDataEncoder.Current.EncodeAndHashTypedData(transactionData, typedDefinition);
}
Safe Hashes Computation:
// GnosisSafeService.cs:132-145
public static SafeHashes GetSafeHashes(
EncodeTransactionDataFunction transactionData,
BigInteger chainId,
string verifyingContractAddress)
{
var typedDefinition = GetGnosisSafeTypedDefinition(chainId, verifyingContractAddress);
var safeDomainHash = Eip712TypedDataEncoder.Current.HashDomainSeparator(typedDefinition);
var safeMessageHash = Eip712TypedDataEncoder.Current.HashStruct(
transactionData, typedDefinition.PrimaryType, typeof(EncodeTransactionDataFunction));
var safeTxnHash = Eip712TypedDataEncoder.Current.EncodeAndHashTypedData(
transactionData, typedDefinition);
return new SafeHashes
{
SafeDomainHash = safeDomainHash,
SafeMessageHash = safeMessageHash,
SafeTxnHash = safeTxnHash
};
}
Multi-Signature Signing:
// GnosisSafeService.cs:198-213
public List<SafeSignature> SignMultipleEncodedTransactionDataHash(
byte[] hashEncoded, params string[] privateKeySigners)
{
var messageSigner = new EthereumMessageSigner();
var signatures = new List<SafeSignature>();
foreach (var privateKey in privateKeySigners)
{
var publicAddress = EthECKey.GetPublicAddress(privateKey);
var signatureString = messageSigner.Sign(hashEncoded, privateKey);
signatureString = ConvertSignatureStringToGnosisVFormat(signatureString);
signatures.Add(new SafeSignature()
{
Address = publicAddress,
Signature = signatureString
});
}
return signatures;
}
Gnosis V Format Conversion:
Gnosis Safe requires signature V values to be offset by +4 from standard Ethereum V values.
// GnosisSafeService.cs:215-225
public static string ConvertSignatureStringToGnosisVFormat(string signatureString)
{
var signature = MessageSigner.ExtractEcdsaSignature(signatureString);
var v = signature.V.ToBigIntegerFromRLPDecoded();
if (VRecoveryAndChainCalculations.IsEthereumV((int)v))
{
signature.V = new[] { (byte)(v + 4) };
signatureString = signature.CreateStringSignature();
}
return signatureString;
}
Signature Ordering:
Gnosis Safe requires signatures to be ordered by signer address.
// GnosisSafeService.cs:258-268
public byte[] GetCombinedSignaturesInOrder(IEnumerable<SafeSignature> signatures)
{
var signaturesFormatted = signatures.Select(
x => ConvertSignatureStringToGnosisVFormat(x.Signature)).ToList();
var orderedSignatures = signaturesFormatted.OrderBy(x => x.ToLower());
var fullSignatures = "0x";
foreach (var signature in orderedSignatures)
{
fullSignatures += signature.RemoveHexPrefix();
}
return fullSignatures.HexToByteArray();
}
Custom ContractHandler that wraps any contract service to execute transactions through a Gnosis Safe (SafeExecTransactionContractHandler.cs:28-124).
Creation:
// SafeExecTransactionContractHandler.cs:30-36
public static SafeExecTransactionContractHandler CreateFromExistingContractService<T>(
T service, string safeAddress, params string[] privateKeySigners)
where T:ContractWeb3ServiceBase
{
var contractAddress = service.ContractAddress;
var ethApiContractService = service.Web3;
var handler = new SafeExecTransactionContractHandler(
contractAddress, safeAddress, ethApiContractService,
service.ContractHandler.AddressFrom, privateKeySigners);
return handler;
}
Transaction Wrapping:
All SendRequestAsync and SendRequestAndWaitForReceiptAsync calls are automatically wrapped in Safe execTransaction calls.
// SafeExecTransactionContractHandler.cs:67-75
public override async Task<TransactionReceipt> SendRequestAndWaitForReceiptAsync<TEthereumContractFunctionMessage>(
TEthereumContractFunctionMessage transactionMessage = null,
CancellationTokenSource tokenSource = null)
{
if (transactionMessage == null) transactionMessage = new TEthereumContractFunctionMessage();
var execTransactionFunction = await CreateExecTransactionFunction(transactionMessage);
return await SafeService.ExecTransactionRequestAndWaitForReceiptAsync(execTransactionFunction);
}
Extension Method:
// SafeExecTransactionContractHandler.cs:21-25
public static void ChangeContractHandlerToSafeExecTransaction<T>(
this T service, string safeAddress, params string[] privateKeySigners)
where T : ContractWeb3ServiceBase
{
service.ContractHandler = SafeExecTransactionContractHandler
.CreateFromExistingContractService(service, safeAddress, privateKeySigners);
}
Account implementation that automatically configures contract services to use SafeExecTransactionContractHandler (SafeAccount.cs:7-21).
// SafeAccount.cs:7-20
public class SafeAccount : Nethereum.Web3.Accounts.Account, IContractServiceConfigurableAccount
{
public SafeAccount(string safeAddress, BigInteger chainId, string privateKey)
: base(privateKey, chainId)
{
SafeAddress = safeAddress;
}
public string SafeAddress { get; }
public void ConfigureContractHandler<T>(T contractService)
where T : ContractWeb3ServiceBase
{
contractService.ChangeContractHandlerToSafeExecTransaction(SafeAddress, this.PrivateKey);
}
}
EncodeTransactionDataFunction (ExtendedContractDefinition.cs:14-118)
EIP-712 SafeTx struct representing a Gnosis Safe transaction:
[Function("encodeTransactionData", "bytes")]
[Struct("SafeTx")]
public class EncodeTransactionDataFunctionBase : FunctionMessage
{
[Parameter("address", "to", 1)]
public string To { get; set; }
[Parameter("uint256", "value", 2)]
public BigInteger Value { get; set; }
[Parameter("bytes", "data", 3)]
public byte[] Data { get; set; }
[Parameter("uint8", "operation", 4)]
public byte Operation { get; set; }
[Parameter("uint256", "safeTxGas", 5)]
public BigInteger SafeTxGas { get; set; }
[Parameter("uint256", "baseGas", 6)]
public BigInteger BaseGas { get; set; }
[Parameter("uint256", "gasPrice", 7)]
public BigInteger SafeGasPrice { get; set; }
[Parameter("address", "gasToken", 8)]
public string GasToken { get; set; }
[Parameter("address", "refundReceiver", 9)]
public string RefundReceiver { get; set; }
[Parameter("uint256", "nonce", 10)]
public BigInteger SafeNonce { get; set; }
}
ExecTransactionFunction (GnosisSafeDefinition.cs:95-120)
Function for executing Safe transactions with signatures:
[Function("execTransaction", "bool")]
public class ExecTransactionFunctionBase : FunctionMessage
{
[Parameter("address", "to", 1)]
public virtual string To { get; set; }
[Parameter("uint256", "value", 2)]
public virtual BigInteger Value { get; set; }
[Parameter("bytes", "data", 3)]
public virtual byte[] Data { get; set; }
[Parameter("uint8", "operation", 4)]
public virtual byte Operation { get; set; }
[Parameter("uint256", "safeTxGas", 5)]
public virtual BigInteger SafeTxGas { get; set; }
[Parameter("uint256", "baseGas", 6)]
public virtual BigInteger BaseGas { get; set; }
[Parameter("uint256", "gasPrice", 7)]
public virtual BigInteger SafeGasPrice { get; set; }
[Parameter("address", "gasToken", 8)]
public virtual string GasToken { get; set; }
[Parameter("address", "refundReceiver", 9)]
public virtual string RefundReceiver { get; set; }
[Parameter("bytes", "signatures", 10)]
public virtual byte[] Signatures { get; set; }
}
GnosisSafeEIP712Domain (GnosisSafeEIP712Domain.cs:7-16)
Custom EIP-712 domain for Safe transactions:
[Struct("EIP712Domain")]
public class GnosisSafeEIP712Domain : IDomain
{
[Parameter("uint256", "chainId", 1)]
public virtual BigInteger? ChainId { get; set; }
[Parameter("address", "verifyingContract", 2)]
public virtual string VerifyingContract { get; set; }
}
using Nethereum.Web3;
using Nethereum.GnosisSafe;
using Nethereum.GnosisSafe.ContractDefinition;
var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_INFURA_KEY");
var safeAddress = "0x..."; // Your Safe address
var chainId = 1;
var safeService = new GnosisSafeService(web3, safeAddress);
// Build transaction
var transactionData = new EncodeTransactionDataFunction
{
To = "0x...", // Target contract
Value = 0,
Data = new byte[] { }, // Encoded function call
Operation = 0, // 0 = Call, 1 = DelegateCall
SafeTxGas = 0,
BaseGas = 0,
SafeGasPrice = 0,
GasToken = "0x0000000000000000000000000000000000000000",
RefundReceiver = "0x0000000000000000000000000000000000000000"
};
// Sign with multiple owners
var privateKey1 = "0x...";
var privateKey2 = "0x...";
var execTx = await safeService.BuildTransactionAsync(
transactionData, chainId, false, privateKey1, privateKey2);
// Execute
var receipt = await safeService.ExecTransactionRequestAndWaitForReceiptAsync(execTx);
using Nethereum.Web3;
using Nethereum.GnosisSafe;
using Nethereum.Contracts;
var privateKey = "0x...";
var safeAddress = "0x...";
var chainId = 1;
// Create SafeAccount
var safeAccount = new SafeAccount(safeAddress, chainId, privateKey);
var web3 = new Web3(safeAccount, "https://mainnet.infura.io/v3/YOUR_INFURA_KEY");
// Any contract service will automatically use Safe execution
var erc20Address = "0x...";
var erc20Service = new Nethereum.Contracts.Standards.ERC20.ERC20ContractService(
web3.Eth, erc20Address);
// This transfer will be executed through the Safe
var transferReceipt = await erc20Service.TransferRequestAndWaitForReceiptAsync(
"0x...", // to
1000000 // amount
);
using Nethereum.Web3;
using Nethereum.GnosisSafe;
using Nethereum.Contracts.Standards.ERC20;
var web3 = new Web3("https://mainnet.infura.io/v3/YOUR_INFURA_KEY");
var safeAddress = "0x...";
var contractAddress = "0x...";
var erc20Service = new ERC20ContractService(web3.Eth, contractAddress);
// Change to Safe execution
var privateKeys = new[] { "0x...", "0x..." };
erc20Service.ChangeContractHandlerToSafeExecTransaction(safeAddress, privateKeys);
// All transactions now go through Safe
var receipt = await erc20Service.TransferRequestAndWaitForReceiptAsync("0x...", 1000);
using Nethereum.GnosisSafe;
using Nethereum.Contracts.TransactionHandlers.MultiSend;
var safeService = new GnosisSafeService(web3, safeAddress);
// Create typed inputs using MultiSendFunctionInput<TFunctionMessage>
// Each input wraps a typed function message with a target contract address
var input1 = new MultiSendFunctionInput<TransferFunction>(
new TransferFunction { To = recipient1, Value = amount1 },
tokenAddress);
var input2 = new MultiSendFunctionInput<TransferFunction>(
new TransferFunction { To = recipient2, Value = amount2 },
tokenAddress);
var transactionData = new EncodeTransactionDataFunction
{
To = multiSendContractAddress,
Value = 0,
SafeTxGas = 0,
BaseGas = 0,
SafeGasPrice = 0,
GasToken = "0x0000000000000000000000000000000000000000",
RefundReceiver = "0x0000000000000000000000000000000000000000"
};
// BuildMultiSendTransactionAsync sets Operation to DelegateCall automatically
var execTx = await safeService.BuildMultiSendTransactionAsync(
transactionData, chainId, privateKey, false, input1, input2);
var receipt = await safeService.ExecTransactionRequestAndWaitForReceiptAsync(execTx);
using Nethereum.GnosisSafe;
var safeService = new GnosisSafeService(web3, safeAddress);
var transactionData = new EncodeTransactionDataFunction
{
To = "0x...",
Value = 0,
Data = new byte[] { },
Operation = 0,
SafeTxGas = 0,
BaseGas = 0,
SafeGasPrice = 0,
GasToken = "0x0000000000000000000000000000000000000000",
RefundReceiver = "0x0000000000000000000000000000000000000000",
SafeNonce = await safeService.NonceQueryAsync()
};
// Sign with current account's private key (EIP-712)
var signature = await safeService.SignEncodedTransactionDataAsync(
transactionData, chainId, convertToSafeVFormat: true);
// Share signature with other owners for off-chain coordination
Console.WriteLine($"Signature: {signature}");
using Nethereum.GnosisSafe;
var transactionData = new EncodeTransactionDataFunction
{
To = "0x...",
Value = 0,
Data = new byte[] { },
Operation = 0,
SafeTxGas = 0,
BaseGas = 0,
SafeGasPrice = 0,
GasToken = "0x0000000000000000000000000000000000000000",
RefundReceiver = "0x0000000000000000000000000000000000000000",
SafeNonce = 5
};
// Get all Safe-related hashes
var safeHashes = GnosisSafeService.GetSafeHashes(
transactionData, chainId, safeAddress);
Console.WriteLine($"Domain Hash: {safeHashes.SafeDomainHash.ToHex()}");
Console.WriteLine($"Message Hash: {safeHashes.SafeMessageHash.ToHex()}");
Console.WriteLine($"Transaction Hash: {safeHashes.SafeTxnHash.ToHex()}");
var safeService = new GnosisSafeService(web3, safeAddress);
// Get current owners
var owners = await safeService.GetOwnersQueryAsync();
var threshold = await safeService.GetThresholdQueryAsync();
Console.WriteLine($"Safe has {owners.Count} owners with threshold {threshold}");
// Add owner (requires Safe transaction execution)
var newOwner = "0x...";
var newThreshold = threshold + 1;
// This call must be executed through the Safe itself
var addOwnerTx = new AddOwnerWithThresholdFunction
{
Owner = newOwner,
Threshold = newThreshold
};
var safeService = new GnosisSafeService(web3, safeAddress);
// Check if module is enabled
var moduleAddress = "0x...";
var isEnabled = await safeService.IsModuleEnabledQueryAsync(moduleAddress);
// Get all modules
var modules = await safeService.GetModulesPaginatedQueryAsync(
"0x0000000000000000000000000000000000000001", // Start
10 // Page size
);
Gnosis Safe uses a custom V value format:
The ConvertSignatureStringToGnosisVFormat method (GnosisSafeService.cs:215-225) handles this conversion automatically.
Safe transactions support advanced gas configuration:
Supports all Nethereum target frameworks. Async methods require .NET Framework 4.5+, .NET Standard 1.1+, or .NET Core 1.0+.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net451 net451 is compatible. net452 net452 was computed. net46 net46 was computed. net461 net461 is compatible. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 1 NuGet packages that depend on Nethereum.GnosisSafe:
| Package | Downloads |
|---|---|
|
Nethereum.Wallet
Core wallet services for managing accounts, vaults, and configuration across the Nethereum stack. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.1.0 | 2,269 | 3/25/2026 |
| 6.0.4 | 376 | 3/18/2026 |
| 6.0.3 | 233 | 3/18/2026 |
| 6.0.1 | 254 | 3/17/2026 |
| 6.0.0 | 251 | 3/16/2026 |
| 5.8.0 | 613 | 1/6/2026 |
| 5.0.0 | 1,680 | 5/28/2025 |
| 4.29.0 | 413 | 2/10/2025 |
| 4.28.0 | 272 | 1/7/2025 |
| 4.27.1 | 259 | 12/24/2024 |
| 4.27.0 | 275 | 12/24/2024 |
| 4.26.0 | 301 | 10/1/2024 |
| 4.25.0 | 287 | 9/19/2024 |
| 4.21.4 | 277 | 8/9/2024 |
| 4.21.3 | 318 | 7/22/2024 |
| 4.21.2 | 303 | 6/26/2024 |
| 4.21.1 | 303 | 6/26/2024 |
| 4.21.0 | 286 | 6/18/2024 |
| 4.20.0 | 313 | 3/28/2024 |
| 4.19.0 | 292 | 2/16/2024 |