Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions Packages/io.chainsafe.web3-unity.web3auth/Runtime/Web3AuthWallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

namespace ChainSafe.GamingSdk.Web3Auth
{
/// <summary>
/// A class that represents a Web3Auth wallet and provides functionality for signing transactions and interacting with a blockchain.
/// </summary>
public class Web3AuthWallet : ISigner, ITransactionExecutor, ILifecycleParticipant
{
private readonly IChainConfig chainConfig;
Expand All @@ -23,13 +26,23 @@ public class Web3AuthWallet : ISigner, ITransactionExecutor, ILifecycleParticipa
private InProcessSigner signer;
private InProcessTransactionExecutor transactionExecutor;

/// <summary>
/// Initializes a new instance of the <see cref="Web3AuthWallet"/> class.
/// </summary>
/// <param name="config">The configuration for the Web3Auth wallet.</param>
/// <param name="chainConfig">The configuration for the target blockchain.</param>
/// <param name="rpcProvider">The RPC provider for blockchain interaction.</param>
public Web3AuthWallet(Web3AuthWalletConfig config, IChainConfig chainConfig, IRpcProvider rpcProvider)
{
this.config = config;
this.chainConfig = chainConfig;
this.rpcProvider = rpcProvider;
}

/// <summary>
/// Asynchronously prepares the Web3Auth wallet for operation, triggered when initializing the module in the dependency injection work flow.
/// </summary>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
public async ValueTask WillStartAsync()
{
coreInstance = CreateCoreInstance();
Expand All @@ -52,6 +65,10 @@ void Web3Auth_OnLogin(Web3AuthResponse response)
}
}

/// <summary>
/// Asynchronously cleans up the Web3Auth wallet and logs out.
/// </summary>
/// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
public async ValueTask WillStopAsync()
{
TaskCompletionSource<object> logoutTcs = new();
Expand All @@ -69,25 +86,34 @@ void Web3Auth_OnLogout()
}
}

public Task<string> GetAddress()
{
return signer.GetAddress();
}

public Task<string> SignMessage(string message)
{
return signer.SignMessage(message);
}

public Task<string> SignTypedData<TStructData>(SerializableDomain domain, TStructData message)
{
return signer.SignTypedData(domain, message);
}

public Task<TransactionResponse> SendTransaction(TransactionRequest transaction)
{
return transactionExecutor.SendTransaction(transaction);
}
/// <summary>
/// Gets the blockchain address associated with this wallet.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns the blockchain address as a string.</returns>
public Task<string> GetAddress() => signer.GetAddress();

/// <summary>
/// Signs a message using the private key associated with this wallet.
/// </summary>
/// <param name="message">The message to sign.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns the signature as a string.</returns>
public Task<string> SignMessage(string message) => signer.SignMessage(message);

/// <summary>
/// Signs an ERC2771 typed data request using the private key associated with this wallet.
/// </summary>
/// <typeparam name="TStructData">The type of the structured data to sign.</typeparam>
/// <param name="domain">The domain information for the typed data.</param>
/// <param name="message">The structured data to sign.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns the signature as a string.</returns>
public Task<string> SignTypedData<TStructData>(SerializableDomain domain, TStructData message) => signer.SignTypedData(domain, message);

/// <summary>
/// Sends a blockchain transaction using the private key associated with this wallet.
/// </summary>
/// <param name="transaction">The transaction request to send.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous operation and returns a <see cref="TransactionResponse"/>.</returns>
public Task<TransactionResponse> SendTransaction(TransactionRequest transaction) => transactionExecutor.SendTransaction(transaction);

private TWeb3Auth CreateCoreInstance()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@

namespace ChainSafe.GamingSdk.Web3Auth
{
/// <summary>
/// Configuration options for initializing a Web3AuthWallet instance.
/// </summary>
public class Web3AuthWalletConfig
{
/// <summary>
/// Gets or sets the Web3AuthOptions for configuring the Web3Auth instance associated with the wallet.
/// </summary>
public Web3AuthOptions Web3AuthOptions { get; set; }

/// <summary>
/// Gets or sets the login parameters for authenticating with the Web3Auth instance. These parameters
/// may include authentication credentials or other required data.
/// </summary>
public LoginParams LoginParams { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,29 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;


/// <summary>
/// A static class providing extension methods to configure and use a Web3AuthWallet within an IWeb3ServiceCollection.
/// </summary>
public static class Web3AuthWalletExtensions
{
/// <summary>
/// Configures and registers a Web3AuthWallet within an IWeb3ServiceCollection with the provided configuration.
/// </summary>
/// <param name="collection">The IWeb3ServiceCollection to configure the Web3AuthWallet within.</param>
/// <param name="configuration">The configuration for the Web3AuthWallet.</param>
/// <returns>The modified IWeb3ServiceCollection with the Web3AuthWallet configuration.</returns>
public static IWeb3ServiceCollection UseWeb3AuthWallet(this IWeb3ServiceCollection collection, Web3AuthWalletConfig configuration)
{
collection.UseWeb3AuthWallet();
collection.ConfigureWeb3AuthWallet(configuration);
return collection;
}

/// <summary>
/// Registers and configures a Web3AuthWallet within an IWeb3ServiceCollection.
/// </summary>
/// <param name="collection">The IWeb3ServiceCollection to register the Web3AuthWallet within.</param>
/// <returns>The modified IWeb3ServiceCollection with the Web3AuthWallet registered.</returns>
public static IWeb3ServiceCollection UseWeb3AuthWallet(this IWeb3ServiceCollection collection)
{
collection.AssertServiceNotBound<ISigner>();
Expand All @@ -26,9 +39,15 @@ public static IWeb3ServiceCollection UseWeb3AuthWallet(this IWeb3ServiceCollecti
return collection;
}

/// <summary>
/// Replaces the existing Web3AuthWallet configuration within an IWeb3ServiceCollection with the provided configuration.
/// </summary>
/// <param name="collection">The IWeb3ServiceCollection to configure the Web3AuthWallet within.</param>
/// <param name="configuration">The configuration for the Web3AuthWallet.</param>
/// <returns>The modified IWeb3ServiceCollection with the Web3AuthWallet configuration replaced.</returns>
public static IWeb3ServiceCollection ConfigureWeb3AuthWallet(this IWeb3ServiceCollection collection, Web3AuthWalletConfig configuration)
{
collection.Replace(ServiceDescriptor.Singleton(typeof(Web3AuthWalletConfig), configuration));
collection.Replace(ServiceDescriptor.Singleton(typeof(Web3AuthWalletConfig), configuration);
return collection;
}
}
19 changes: 19 additions & 0 deletions src/ChainSafe.Gaming.Tests/ChainlinkLootboxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@

namespace ChainSafe.Gaming.Evm.Tests
{
/// <summary>
/// Test fixture for testing the Chainlink Lootbox functionality.
/// </summary>
[TestFixture]
public class ChainlinkLootboxTests // todo: not sure if should assert default network values
{
private Web3.Web3 web3;

// todo add automatic emulator boot up
/// <summary>
/// Sets up the Web3 instance and other necessary configurations for testing Chainlink Lootboxes.
/// </summary>
[OneTimeSetUp]
public void Setup()
{
Expand All @@ -35,11 +41,17 @@ public void Setup()
web3 = web3BuildTask.Result;
}

/// <summary>
/// Tears down the test fixture after all tests are executed.
/// </summary>
[OneTimeTearDown]
public void TearDown()
{
}

/// <summary>
/// Tests the retrieval of lootbox types from the Chainlink Lootbox service.
/// </summary>
[Test]
public async Task GetLootboxTypesTest()
{
Expand Down Expand Up @@ -102,6 +114,10 @@ public async Task CalculateOpenPriceTest()
// $"{nameof(ILootboxService.CanClaimRewards)} to become true.");
// }
// }

/// <summary>
/// Test method to verify that 'OpenInProgress' is true when a lootbox is being opened.
/// </summary>
[Test]
public async Task OpenInProgressIsTrueWhenOpeningTest()
{
Expand All @@ -111,6 +127,9 @@ public async Task OpenInProgressIsTrueWhenOpeningTest()
Assert.IsTrue(openInProgress);
}

/// <summary>
/// Test method to verify that 'OpenInProgress' is false when no lootbox is being opened.
/// </summary>
[Test]
public async Task OpenInProgressIsFalseWhenNotOpeningTest()
{
Expand Down
64 changes: 64 additions & 0 deletions src/ChainSafe.Gaming.Tests/ChainsafeRPCTests.cs

Large diffs are not rendered by default.

33 changes: 30 additions & 3 deletions src/ChainSafe.Gaming.Tests/ProvidersSendTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,26 @@ namespace ChainSafe.Gaming.Tests
using static RpcProviderExtensions;
using Web3 = ChainSafe.Gaming.Web3.Web3;

/// <summary>
/// Test class for testing various aspects of sending transactions using Web3 providers.
/// </summary>
[TestFixture]
public class ProvidersSendTests
{
private Web3 firstAccount;
private Web3 secondAccount;
private Process node;

/// <summary>
/// One-time setup method that initializes the test environment and resources.
/// </summary>
[OneTimeSetUp]
public void SetUp()
{
// Create a local Ethereum node emulator for testing.
node = Emulator.CreateInstance();

// Create Web3 instances for the first and second accounts.
var firstAccountTask = CreateWeb3(0).AsTask();
firstAccountTask.Wait();
firstAccount = firstAccountTask.Result;
Expand All @@ -33,31 +41,42 @@ public void SetUp()
secondAccount = secondAccountTask.Result;
}

/// <summary>
/// One-time teardown method to clean up and release any resources after all tests have executed.
/// </summary>
[OneTimeTearDown]
public void Cleanup()
{
node?.Kill();
}

/// <summary>
/// Test method to validate sending a transaction from one account to another.
/// </summary>
[Test]
public void SendTransactionTest()
{
// Get initial balances and addresses for both sender and receiver accounts.
var fromAddress = firstAccount.Signer.GetAddress().Result;
var fromInitialBalance = firstAccount.RpcProvider.GetBalance(fromAddress).Result.Value;

var toAddress = secondAccount.Signer.GetAddress().Result;
var toInitialBalance = firstAccount.RpcProvider.GetBalance(toAddress).Result.Value;

var amount = new HexBigInteger(1000000);

// Send a transaction from the first account to the second account.
var tx = firstAccount.TransactionExecutor.SendTransaction(new TransactionRequest
{
To = toAddress,
Value = amount,
});
tx.Wait();

// Verify the transaction hash and its properties.
Assert.True(tx.Result.Hash.StartsWith("0x"));

// Retrieve the transaction receipt and perform additional assertions.
var txReceipt = firstAccount.RpcProvider.GetTransactionReceipt(tx.Result.Hash);
txReceipt.Wait();

Expand All @@ -68,6 +87,9 @@ public void SendTransactionTest()
firstAccount.RpcProvider.GetBalance(fromAddress).Result.Value);
}

/// <summary>
/// Test method to verify sending a transaction with an invalid destination address.
/// </summary>
[Test]
public void SendTransactionWithInvalidAddress()
{
Expand All @@ -85,9 +107,13 @@ public void SendTransactionWithInvalidAddress()
{
var txHash = await firstAccount.TransactionExecutor.SendTransaction(transaction);
});

Assert.That(ex.Message.Contains("eth_sendTransaction"));
}

/// <summary>
/// Test method to validate sending a transaction with an insufficient gas limit.
/// </summary>
[Test]
public void SendTransactionWithLowGasLimit()
{
Expand All @@ -107,10 +133,11 @@ public void SendTransactionWithLowGasLimit()
});

Assert.That(ex != null && ex.Message.Contains("eth_sendTransaction"));
var result = ex.InnerException != null;
Assert.That(result);
}

/// <summary>
/// Test method to validate sending a transaction with a very low gas price.
/// </summary>
[Test]
public void SendTransactionWithLowGasPrice()
{
Expand All @@ -127,4 +154,4 @@ public void SendTransactionWithLowGasPrice()
Assert.ThrowsAsync<Web3Exception>(() => firstAccount.TransactionExecutor.SendTransaction(transaction));
}
}
}
}
27 changes: 27 additions & 0 deletions src/ChainSafe.Gaming.Tests/Web3Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,38 @@

namespace ChainSafe.Gaming.Tests
{
/// <summary>
/// A utility class for working with Web3 instances and deploying smart contracts.
/// </summary>
internal static class Web3Util
{
/// <summary>
/// Creates a new Web3 instance using default settings and an optional account index.
/// </summary>
/// <param name="accountIndex">An optional account index.</param>
/// <returns>A ValueTask of Web3.Web3.</returns>
public static ValueTask<Web3.Web3> CreateWeb3(int accountIndex = 0)
{
return CreateWeb3(new JsonRpcWalletConfig { AccountIndex = accountIndex });
}

/// <summary>
/// Creates a new Web3 instance with custom configurations and an optional account index.
/// </summary>
/// <param name="configureDelegate">A delegate to configure services.</param>
/// <param name="accountIndex">An optional account index.</param>
/// <returns>A ValueTask of Web3.Web3.</returns>
public static ValueTask<Web3.Web3> CreateWeb3(Web3Builder.ConfigureServicesDelegate configureDelegate, int accountIndex = 0)
{
return CreateWeb3(new JsonRpcWalletConfig { AccountIndex = accountIndex }, configureDelegate);
}

/// <summary>
/// Creates a new Web3 instance with custom configurations.
/// </summary>
/// <param name="jsonRpcWalletConfig">The JSON-RPC wallet configuration.</param>
/// <param name="configureDelegate">A delegate to configure services.</param>
/// <returns>A ValueTask of Web3.Web3.</returns>
private static ValueTask<Web3.Web3> CreateWeb3(
JsonRpcWalletConfig jsonRpcWalletConfig, Web3Builder.ConfigureServicesDelegate configureDelegate = null)
{
Expand All @@ -48,6 +68,13 @@ internal static class Web3Util
.BuildAsync();
}

/// <summary>
/// Deploys smart contracts using the provided Web3 instance, bytecode, and ABI.
/// </summary>
/// <param name="web3">The Web3 instance.</param>
/// <param name="bytecode">The bytecode of the smart contract.</param>
/// <param name="abi">The ABI (Application Binary Interface) of the smart contract.</param>
/// <returns>The contract address of the deployed smart contract.</returns>
public static string DeployContracts(Web3.Web3 web3, string bytecode, string abi)
{
var builder = new DeployContractTransactionBuilder();
Expand Down