From 8f125210de0e255ce2dd57e1f1b4a5a145fa63c9 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Wed, 10 Apr 2024 03:26:22 +0300 Subject: [PATCH] Refactor everything, simpler api (#14) * Refactor everything, simpler api * isvalid and personal raw --- README.md | 96 ++++------ Thirdweb.Console/Program.cs | 62 +++--- Thirdweb.Tests/Thirdweb.Client.Tests.cs | 18 +- Thirdweb.Tests/Thirdweb.Contracts.Tests.cs | 75 +++----- .../Thirdweb.PrivateKeyAccount.Tests.cs | 97 ++++------ Thirdweb.Tests/Thirdweb.RPC.Tests.cs | 16 +- Thirdweb.Tests/Thirdweb.SmartAccount.Tests.cs | 53 +++--- Thirdweb.Tests/Thirdweb.Storage.Tests.cs | 22 +-- Thirdweb.Tests/Thirdweb.Utils.Tests.cs | 6 +- Thirdweb.Tests/Thirdweb.Wallets.Tests.cs | 102 +++------- Thirdweb/Thirdweb.Client/ThirdwebClient.cs | 8 +- .../Thirdweb.Contracts/ThirdwebContract.cs | 37 ++-- Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs | 2 +- .../EmbeddedAccount/EmbeddedAccount.cs | 179 ++---------------- Thirdweb/Thirdweb.Wallets/IThirdwebAccount.cs | 4 +- .../PrivateKeyAccount/PrivateKeyAccount.cs | 40 ++-- .../SmartAccount/SmartAccount.cs | 107 ++++++----- Thirdweb/Thirdweb.Wallets/ThirdwebWallet.cs | 95 ---------- 18 files changed, 336 insertions(+), 683 deletions(-) delete mode 100644 Thirdweb/Thirdweb.Wallets/ThirdwebWallet.cs diff --git a/README.md b/README.md index 4125657..b7c4ef9 100644 --- a/README.md +++ b/README.md @@ -26,21 +26,19 @@ dotnet add package Thirdweb **Simple Example** ```csharp -// Generate a thirdweb client -var client = new ThirdwebClient(clientId: "myClientId", bundleId: "com.my.bundleid"); +// A single client fits most use cases +var client = ThirdwebClient.Create(clientId: "myClientId", bundleId: "com.my.bundleid"); -// Define a contract -var abi = await ThirdwebContract.FetchAbi("0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", 1); // helper in case you don't have abi on hand -var contract = new ThirdwebContract(client: client, address: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", chain: 1, abi: abi); - -// Read from any contract -var readResult = await ThirdwebContract.ReadContract(contract, "name"); +// Optionally pass abi, if not passed we fetch it for you +var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); +var readResult = await ThirdwebContract.Read(contract, "name"); Console.WriteLine($"Contract read result: {readResult}"); -// Generate a persistent cross platform EOA to act as a signer -var embeddedAccount = new EmbeddedAccount(client: client, email: "email@email.com"); // or email: null, phoneNumber: "+1234567890" -await embeddedAccount.Connect(); -// If no previous session exists +// Create a smart account to unlock gasless features, with an embedded account as signer to unlock web2 auth +var embeddedAccount = await EmbeddedAccount.Create(client: client, email: "email@email.com"); // or email: null, phoneNumber: "+1234567890" +var smartAccount = await SmartAccount.Create(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + +// Relog if embedded account not logged in if (!await embeddedAccount.IsConnected()) { await embeddedAccount.SendOTP(); @@ -60,18 +58,17 @@ if (!await embeddedAccount.IsConnected()) } } -// Finally, upgrade that signer to a Smart Account to unlock onchain features such as gasless txs and session keys out of the box -var smartAccount = new SmartAccount(client: client, personalAccount: embeddedAccount, factoryAddress: "mySmartAccountFactory", gasless: true, chainId: 421614); -await smartAccount.Connect(); +// Log addresses +Console.WriteLine($"Embedded Account: {await embeddedAccount.GetAddress()}"); +Console.WriteLine($"Smart Account: {await smartAccount.GetAddress()}"); -// Generate a top level wallet for users (wallets may contain multiple accounts, but don't have to) -var thirdwebWallet = new ThirdwebWallet(); -await thirdwebWallet.Initialize(new List { smartAccount }); +// Sign, triggering deploy as needed and 1271 verification if it's a smart wallet +var message = "Hello, Thirdweb!"; +var signature = await smartAccount.PersonalSign(message); +Console.WriteLine($"Signed message: {signature}"); -// Write to any contract! -var writeResult = await ThirdwebContract.WriteContract(thirdwebWallet, contract, "mintTo", 0, await thirdwebWallet.GetAddress(), 100); +var writeResult = await ThirdwebContract.Write(smartAccount, contract, "mintTo", 0, await smartAccount.GetAddress(), 100); Console.WriteLine($"Contract write result: {writeResult}"); - ``` **Advanced Example** @@ -85,32 +82,22 @@ var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); // Fetch timeout options are optional, default is 60000ms -var client = new ThirdwebClient(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); - -// Access RPC directly if needed, generally not recommended -// var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); -// var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); -// Console.WriteLine($"Block number: {blockNumber}"); +var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); -// Interact with a contract -var contract = new ThirdwebContract(client: client, address: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", chain: 1, abi: "MyC#EscapedContractABI"); -var readResult = await ThirdwebContract.ReadContract(contract, "name"); +var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); +var readResult = await ThirdwebContract.Read(contract, "name"); Console.WriteLine($"Contract read result: {readResult}"); // Create accounts (this is an advanced use case, typically one account is plenty) -var privateKeyAccount = new PrivateKeyAccount(client: client, privateKeyHex: privateKey); -var embeddedAccount = new EmbeddedAccount(client: client, email: "firekeeper+7121271d@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" -var smartAccount = new SmartAccount(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); +var privateKeyAccount = await PrivateKeyAccount.Create(client: client, privateKeyHex: privateKey); +var embeddedAccount = await EmbeddedAccount.Create(client: client, email: "email@email.com"); // or email: null, phoneNumber: "+1234567890" +var smartAccount = await SmartAccount.Create(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); -// Attempt to connect pk accounts -await privateKeyAccount.Connect(); -await embeddedAccount.Connect(); - -// Reset embedded account (optional step for testing login flow) -if (await embeddedAccount.IsConnected()) -{ - await embeddedAccount.Disconnect(); -} +// // Reset embedded account (optional step for testing login flow) +// if (await embeddedAccount.IsConnected()) +// { +// await embeddedAccount.Disconnect(); +// } // Relog if embedded account not logged in if (!await embeddedAccount.IsConnected()) @@ -133,7 +120,6 @@ if (!await embeddedAccount.IsConnected()) } // Connect the smart account with embedded signer and grant a session key to pk account (advanced use case) -await smartAccount.Connect(); _ = await smartAccount.CreateSessionKey( signerAddress: await privateKeyAccount.GetAddress(), approvedTargets: new List() { Constants.ADDRESS_ZERO }, @@ -145,7 +131,7 @@ _ = await smartAccount.CreateSessionKey( ); // Reconnect to same smart account with pk account as signer (specifying account address override) -smartAccount = new SmartAccount( +smartAccount = await SmartAccount.Create( client: client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", @@ -153,31 +139,24 @@ smartAccount = new SmartAccount( chainId: 421614, accountAddressOverride: await smartAccount.GetAddress() ); -await smartAccount.Connect(); // Log addresses Console.WriteLine($"PrivateKey Account: {await privateKeyAccount.GetAddress()}"); Console.WriteLine($"Embedded Account: {await embeddedAccount.GetAddress()}"); Console.WriteLine($"Smart Account: {await smartAccount.GetAddress()}"); -// Initialize wallet (a wallet can hold multiple accounts, but only one can be active at a time) -var thirdwebWallet = new ThirdwebWallet(); -await thirdwebWallet.Initialize(new List { privateKeyAccount, embeddedAccount, smartAccount }); -thirdwebWallet.SetActive(await smartAccount.GetAddress()); -Console.WriteLine($"Active account: {await thirdwebWallet.GetAddress()}"); - // Sign, triggering deploy as needed and 1271 verification if it's a smart wallet var message = "Hello, Thirdweb!"; -var signature = await thirdwebWallet.PersonalSign(message); +var signature = await smartAccount.PersonalSign(message); Console.WriteLine($"Signed message: {signature}"); -var balanceBefore = await ThirdwebContract.ReadContract(contract, "balanceOf", await thirdwebWallet.GetAddress()); +var balanceBefore = await ThirdwebContract.Read(contract, "balanceOf", await smartAccount.GetAddress()); Console.WriteLine($"Balance before mint: {balanceBefore}"); -var writeResult = await ThirdwebContract.WriteContract(thirdwebWallet, contract, "mintTo", 0, await thirdwebWallet.GetAddress(), 100); +var writeResult = await ThirdwebContract.Write(smartAccount, contract, "mintTo", 0, await smartAccount.GetAddress(), 100); Console.WriteLine($"Contract write result: {writeResult}"); -var balanceAfter = await ThirdwebContract.ReadContract(contract, "balanceOf", await thirdwebWallet.GetAddress()); +var balanceAfter = await ThirdwebContract.Read(contract, "balanceOf", await smartAccount.GetAddress()); Console.WriteLine($"Balance after mint: {balanceAfter}"); // Storage actions @@ -189,4 +168,11 @@ Console.WriteLine($"Balance after mint: {balanceAfter}"); // // Will upload to IPFS // var uploadResult = await ThirdwebStorage.Upload(client: client, path: "AnyPath"); // Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}"); + + +// Access RPC directly if needed, generally not recommended + +// var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); +// var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); +// Console.WriteLine($"Block number: {blockNumber}"); ``` diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 2430ac6..06cc550 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -1,6 +1,5 @@ using System.Numerics; using dotenv.net; -using Newtonsoft.Json; using Thirdweb; internal class Program @@ -15,36 +14,22 @@ private static async Task Main(string[] args) var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); // Fetch timeout options are optional, default is 60000ms - var client = new ThirdwebClient(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); + var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); - // Access RPC directly if needed, generally not recommended - // var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); - // var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); - // Console.WriteLine($"Block number: {blockNumber}"); - - var contract = new ThirdwebContract( - client: client, - address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", - chain: 421614, - abi: "[{\"type\": \"constructor\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"event\",\"name\": \"Approval\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"spender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"value\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"DelegateChanged\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegator\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"fromDelegate\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"toDelegate\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"DelegateVotesChanged\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegate\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"previousBalance\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"newBalance\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"EIP712DomainChanged\",\"inputs\": [],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FlatPlatformFeeUpdated\",\"inputs\": [{\"type\": \"address\",\"name\": \"platformFeeRecipient\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"flatFee\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Initialized\",\"inputs\": [{\"type\": \"uint8\",\"name\": \"version\",\"indexed\": false,\"internalType\": \"uint8\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PlatformFeeInfoUpdated\",\"inputs\": [{\"type\": \"address\",\"name\": \"platformFeeRecipient\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"platformFeeBps\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PlatformFeeTypeUpdated\",\"inputs\": [{\"type\": \"uint8\",\"name\": \"feeType\",\"indexed\": false,\"internalType\": \"enum IPlatformFee.PlatformFeeType\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PrimarySaleRecipientUpdated\",\"inputs\": [{\"type\": \"address\",\"name\": \"recipient\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleAdminChanged\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"previousAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"newAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleGranted\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleRevoked\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"TokensMinted\",\"inputs\": [{\"type\": \"address\",\"name\": \"mintedTo\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"quantityMinted\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"TokensMintedWithSignature\",\"inputs\": [{\"type\": \"address\",\"name\": \"signer\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"mintedTo\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"tuple\",\"name\": \"mintRequest\",\"components\": [{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"primarySaleRecipient\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"quantity\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"price\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"},{\"type\": \"uint128\",\"name\": \"validityStartTimestamp\",\"internalType\": \"uint128\"},{\"type\": \"uint128\",\"name\": \"validityEndTimestamp\",\"internalType\": \"uint128\"},{\"type\": \"bytes32\",\"name\": \"uid\",\"internalType\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct ITokenERC20.MintRequest\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Transfer\",\"inputs\": [{\"type\": \"address\",\"name\": \"from\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"to\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"value\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"function\",\"name\": \"CLOCK_MODE\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"DEFAULT_ADMIN_ROLE\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"DOMAIN_SEPARATOR\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"allowance\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"approve\",\"inputs\": [{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"balanceOf\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"burn\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"burnFrom\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"checkpoints\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"},{\"type\": \"uint32\",\"name\": \"pos\",\"internalType\": \"uint32\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"uint32\",\"name\": \"fromBlock\",\"internalType\": \"uint32\"},{\"type\": \"uint224\",\"name\": \"votes\",\"internalType\": \"uint224\"}],\"internalType\": \"struct ERC20VotesUpgradeable.Checkpoint\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"clock\",\"inputs\": [],\"outputs\": [{\"type\": \"uint48\",\"name\": \"\",\"internalType\": \"uint48\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"contractType\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"pure\"},{\"type\": \"function\",\"name\": \"contractURI\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"contractVersion\",\"inputs\": [],\"outputs\": [{\"type\": \"uint8\",\"name\": \"\",\"internalType\": \"uint8\"}],\"stateMutability\": \"pure\"},{\"type\": \"function\",\"name\": \"decimals\",\"inputs\": [],\"outputs\": [{\"type\": \"uint8\",\"name\": \"\",\"internalType\": \"uint8\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"decreaseAllowance\",\"inputs\": [{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"subtractedValue\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"delegate\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegatee\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"delegateBySig\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegatee\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"expiry\",\"internalType\": \"uint256\"},{\"type\": \"uint8\",\"name\": \"v\",\"internalType\": \"uint8\"},{\"type\": \"bytes32\",\"name\": \"r\",\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"s\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"delegates\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"eip712Domain\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes1\",\"name\": \"fields\",\"internalType\": \"bytes1\"},{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"version\",\"internalType\": \"string\"},{\"type\": \"uint256\",\"name\": \"chainId\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"verifyingContract\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"salt\",\"internalType\": \"bytes32\"},{\"type\": \"uint256[]\",\"name\": \"extensions\",\"internalType\": \"uint256[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getPastTotalSupply\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"timepoint\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getPastVotes\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"timepoint\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getPlatformFeeInfo\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"},{\"type\": \"uint16\",\"name\": \"\",\"internalType\": \"uint16\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleAdmin\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMember\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"index\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMemberCount\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getVotes\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"grantRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"hasRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"increaseAllowance\",\"inputs\": [{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"addedValue\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"initialize\",\"inputs\": [{\"type\": \"address\",\"name\": \"_defaultAdmin\",\"internalType\": \"address\"},{\"type\": \"string\",\"name\": \"_name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"_symbol\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"_contractURI\",\"internalType\": \"string\"},{\"type\": \"address[]\",\"name\": \"_trustedForwarders\",\"internalType\": \"address[]\"},{\"type\": \"address\",\"name\": \"_primarySaleRecipient\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"_platformFeeRecipient\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_platformFeeBps\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"isTrustedForwarder\",\"inputs\": [{\"type\": \"address\",\"name\": \"forwarder\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"mintTo\",\"inputs\": [{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"mintWithSignature\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_req\",\"components\": [{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"primarySaleRecipient\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"quantity\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"price\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"},{\"type\": \"uint128\",\"name\": \"validityStartTimestamp\",\"internalType\": \"uint128\"},{\"type\": \"uint128\",\"name\": \"validityEndTimestamp\",\"internalType\": \"uint128\"},{\"type\": \"bytes32\",\"name\": \"uid\",\"internalType\": \"bytes32\"}],\"internalType\": \"struct ITokenERC20.MintRequest\"},{\"type\": \"bytes\",\"name\": \"_signature\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"multicall\",\"inputs\": [{\"type\": \"bytes[]\",\"name\": \"data\",\"internalType\": \"bytes[]\"}],\"outputs\": [{\"type\": \"bytes[]\",\"name\": \"results\",\"internalType\": \"bytes[]\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"name\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"nonces\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"numCheckpoints\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint32\",\"name\": \"\",\"internalType\": \"uint32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"permit\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"value\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"deadline\",\"internalType\": \"uint256\"},{\"type\": \"uint8\",\"name\": \"v\",\"internalType\": \"uint8\"},{\"type\": \"bytes32\",\"name\": \"r\",\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"s\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"primarySaleRecipient\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"renounceRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"revokeRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setContractURI\",\"inputs\": [{\"type\": \"string\",\"name\": \"_uri\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setPlatformFeeInfo\",\"inputs\": [{\"type\": \"address\",\"name\": \"_platformFeeRecipient\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_platformFeeBps\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setPrimarySaleRecipient\",\"inputs\": [{\"type\": \"address\",\"name\": \"_saleRecipient\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"supportsInterface\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"interfaceId\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"symbol\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"totalSupply\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"transfer\",\"inputs\": [{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"transferFrom\",\"inputs\": [{\"type\": \"address\",\"name\": \"from\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"verify\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_req\",\"components\": [{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"primarySaleRecipient\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"quantity\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"price\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"},{\"type\": \"uint128\",\"name\": \"validityStartTimestamp\",\"internalType\": \"uint128\"},{\"type\": \"uint128\",\"name\": \"validityEndTimestamp\",\"internalType\": \"uint128\"},{\"type\": \"bytes32\",\"name\": \"uid\",\"internalType\": \"bytes32\"}],\"internalType\": \"struct ITokenERC20.MintRequest\"},{\"type\": \"bytes\",\"name\": \"_signature\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"},{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"}]" - ); - var readResult = await ThirdwebContract.ReadContract(contract, "name"); + var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); + var readResult = await ThirdwebContract.Read(contract, "name"); Console.WriteLine($"Contract read result: {readResult}"); // Create accounts (this is an advanced use case, typically one account is plenty) - var privateKeyAccount = new PrivateKeyAccount(client: client, privateKeyHex: privateKey); - var embeddedAccount = new EmbeddedAccount(client: client, email: "firekeeper+7121271d@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" - var smartAccount = new SmartAccount(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + var privateKeyAccount = await PrivateKeyAccount.Create(client: client, privateKeyHex: privateKey); + var embeddedAccount = await EmbeddedAccount.Create(client: client, email: "firekeeper+7121271d@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" + var smartAccount = await SmartAccount.Create(client: client, personalAccount: embeddedAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - // Attempt to connect pk accounts - await privateKeyAccount.Connect(); - await embeddedAccount.Connect(); - - // Reset embedded account (optional step for testing login flow) - if (await embeddedAccount.IsConnected()) - { - await embeddedAccount.Disconnect(); - } + // // Reset embedded account (optional step for testing login flow) + // if (await embeddedAccount.IsConnected()) + // { + // await embeddedAccount.Disconnect(); + // } // Relog if embedded account not logged in if (!await embeddedAccount.IsConnected()) @@ -67,7 +52,6 @@ private static async Task Main(string[] args) } // Connect the smart account with embedded signer and grant a session key to pk account (advanced use case) - await smartAccount.Connect(); _ = await smartAccount.CreateSessionKey( signerAddress: await privateKeyAccount.GetAddress(), approvedTargets: new List() { Constants.ADDRESS_ZERO }, @@ -79,7 +63,7 @@ private static async Task Main(string[] args) ); // Reconnect to same smart account with pk account as signer (specifying account address override) - smartAccount = new SmartAccount( + smartAccount = await SmartAccount.Create( client: client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", @@ -87,31 +71,24 @@ private static async Task Main(string[] args) chainId: 421614, accountAddressOverride: await smartAccount.GetAddress() ); - await smartAccount.Connect(); // Log addresses Console.WriteLine($"PrivateKey Account: {await privateKeyAccount.GetAddress()}"); Console.WriteLine($"Embedded Account: {await embeddedAccount.GetAddress()}"); Console.WriteLine($"Smart Account: {await smartAccount.GetAddress()}"); - // Initialize wallet (a wallet can hold multiple accounts, but only one can be active at a time) - var thirdwebWallet = new ThirdwebWallet(); - await thirdwebWallet.Initialize(new List { privateKeyAccount, embeddedAccount, smartAccount }); - thirdwebWallet.SetActive(await smartAccount.GetAddress()); - Console.WriteLine($"Active account: {await thirdwebWallet.GetAddress()}"); - // Sign, triggering deploy as needed and 1271 verification if it's a smart wallet var message = "Hello, Thirdweb!"; - var signature = await thirdwebWallet.PersonalSign(message); + var signature = await smartAccount.PersonalSign(message); Console.WriteLine($"Signed message: {signature}"); - var balanceBefore = await ThirdwebContract.ReadContract(contract, "balanceOf", await thirdwebWallet.GetAddress()); + var balanceBefore = await ThirdwebContract.Read(contract, "balanceOf", await smartAccount.GetAddress()); Console.WriteLine($"Balance before mint: {balanceBefore}"); - var writeResult = await ThirdwebContract.WriteContract(thirdwebWallet, contract, "mintTo", 0, await thirdwebWallet.GetAddress(), 100); + var writeResult = await ThirdwebContract.Write(smartAccount, contract, "mintTo", 0, await smartAccount.GetAddress(), 100); Console.WriteLine($"Contract write result: {writeResult}"); - var balanceAfter = await ThirdwebContract.ReadContract(contract, "balanceOf", await thirdwebWallet.GetAddress()); + var balanceAfter = await ThirdwebContract.Read(contract, "balanceOf", await smartAccount.GetAddress()); Console.WriteLine($"Balance after mint: {balanceAfter}"); // Storage actions @@ -123,5 +100,12 @@ private static async Task Main(string[] args) // // Will upload to IPFS // var uploadResult = await ThirdwebStorage.Upload(client: client, path: "AnyPath"); // Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}"); + + + // Access RPC directly if needed, generally not recommended + + // var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); + // var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); + // Console.WriteLine($"Block number: {blockNumber}"); } } diff --git a/Thirdweb.Tests/Thirdweb.Client.Tests.cs b/Thirdweb.Tests/Thirdweb.Client.Tests.cs index a6c148d..e9c27cc 100644 --- a/Thirdweb.Tests/Thirdweb.Client.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Client.Tests.cs @@ -8,13 +8,13 @@ public ClientTests(ITestOutputHelper output) [Fact] public void NoSecretKeyNoClientId() { - Assert.Throws(() => new ThirdwebClient()); + Assert.Throws(() => ThirdwebClient.Create()); } [Fact] public void SecretKeyInitialization() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); Assert.NotNull(client.ClientId); Assert.NotNull(client.SecretKey); Assert.Null(client.BundleId); @@ -26,7 +26,7 @@ public void SecretKeyInitialization() public void ClientIdInitialization() { var clientId = "test-client-id"; - var client = new ThirdwebClient(clientId: clientId); + var client = ThirdwebClient.Create(clientId: clientId); Assert.NotNull(client.ClientId); Assert.Null(client.SecretKey); Assert.Null(client.BundleId); @@ -37,7 +37,7 @@ public void ClientIdInitialization() public void BundleIdInitialization() { var bundleId = "test-bundle-id"; - var exception = Assert.Throws(() => new ThirdwebClient(bundleId: bundleId)); + var exception = Assert.Throws(() => ThirdwebClient.Create(bundleId: bundleId)); Assert.Equal("ClientId or SecretKey must be provided", exception.Message); } @@ -45,7 +45,7 @@ public void BundleIdInitialization() public void ClientIdAndSecretKeyInitialization() { var clientId = "test-client-id"; - var client = new ThirdwebClient(clientId: clientId, secretKey: _secretKey); + var client = ThirdwebClient.Create(clientId: clientId, secretKey: _secretKey); Assert.NotNull(client.ClientId); Assert.NotNull(client.SecretKey); Assert.Null(client.BundleId); @@ -59,7 +59,7 @@ public void ClientIdAndBundleIdInitialization() { var clientId = "test-client-id"; var bundleId = "test-bundle-id"; - var client = new ThirdwebClient(clientId: clientId, bundleId: bundleId); + var client = ThirdwebClient.Create(clientId: clientId, bundleId: bundleId); Assert.NotNull(client.ClientId); Assert.NotNull(client.BundleId); Assert.Null(client.SecretKey); @@ -71,7 +71,7 @@ public void ClientIdAndBundleIdInitialization() public void SecretKeyAndBundleIdInitialization() { var bundleId = "test-bundle-id"; - var client = new ThirdwebClient(secretKey: _secretKey, bundleId: bundleId); + var client = ThirdwebClient.Create(secretKey: _secretKey, bundleId: bundleId); Assert.NotNull(client.SecretKey); Assert.NotNull(client.BundleId); Assert.NotNull(client.ClientId); @@ -83,7 +83,7 @@ public void SecretKeyAndBundleIdInitialization() [Fact] public void TimeoutOptions() { - var client = new ThirdwebClient(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000)); + var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000)); Assert.NotNull(client.FetchTimeoutOptions); Assert.Equal(30000, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); Assert.Equal(30000, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); @@ -94,7 +94,7 @@ public void TimeoutOptions() [Fact] public void NoTimeoutOptions() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); Assert.NotNull(client.FetchTimeoutOptions); Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); diff --git a/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs index 12dc33b..d782521 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs @@ -17,46 +17,46 @@ public async Task FetchAbi() } [Fact] - public void InitTest_NullClient() + public async Task InitTest_NullClient() { - var exception = Assert.Throws(() => new ThirdwebContract(null, "0x123", 1, "[]")); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(null, "0x123", 1, "[]")); Assert.Contains("Client must be provided", exception.Message); } [Fact] - public void InitTest_NullAddress() + public async Task InitTest_NullAddress() { - var exception = Assert.Throws(() => new ThirdwebContract(new ThirdwebClient(secretKey: _secretKey), null, 1, "[]")); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), null, 1, "[]")); Assert.Contains("Address must be provided", exception.Message); } [Fact] - public void InitTest_ZeroChain() + public async Task InitTest_ZeroChain() { - var exception = Assert.Throws(() => new ThirdwebContract(new ThirdwebClient(secretKey: _secretKey), "0x123", 0, "[]")); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x123", 0, "[]")); Assert.Contains("Chain must be provided", exception.Message); } [Fact] - public void InitTest_NullAbi() + public async Task InitTest_NullAbi() { - var exception = Assert.Throws(() => new ThirdwebContract(new ThirdwebClient(secretKey: _secretKey), "0x123", 1, null)); - Assert.Contains("Abi must be provided", exception.Message); + var res = await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", 421614, null); + Assert.NotNull(res); } [Fact] public async Task ReadTest_String() { - var contract = GetContract(); - var result = await ThirdwebContract.ReadContract(contract, "name"); + var contract = await GetContract(); + var result = await ThirdwebContract.Read(contract, "name"); Assert.Equal("Kitty DropERC20", result); } [Fact] public async Task ReadTest_BigInteger() { - var contract = GetContract(); - var result = await ThirdwebContract.ReadContract(contract, "decimals"); + var contract = await GetContract(); + var result = await ThirdwebContract.Read(contract, "decimals"); Assert.Equal(18, result); } @@ -73,8 +73,8 @@ private class GetPlatformFeeInfoOutputDTO : Nethereum.ABI.FunctionEncoding.Attri [Fact] public async Task ReadTest_Tuple() { - var contract = GetContract(); - var result = await ThirdwebContract.ReadContract(contract, "getPlatformFeeInfo"); + var contract = await GetContract(); + var result = await ThirdwebContract.Read(contract, "getPlatformFeeInfo"); Assert.Equal("0xDaaBDaaC8073A7dAbdC96F6909E8476ab4001B34", result.ReturnValue1); Assert.Equal(0, result.ReturnValue2); } @@ -90,15 +90,15 @@ private class AllowlistProof [Fact] public async Task WriteTest_SmartAccount() { - var contract = GetContract(); - var wallet = await GetWallet(); - var receiver = await wallet.GetAddress(); + var contract = await GetContract(); + var smartAccount = await GetAccount(); + var receiver = await smartAccount.GetAddress(); var quantity = BigInteger.One; var currency = Constants.NATIVE_TOKEN_ADDRESS; var pricePerToken = BigInteger.Zero; var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; var data = new byte[] { }; - var result = await ThirdwebContract.WriteContract(wallet, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data); + var result = await ThirdwebContract.Write(smartAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data); Assert.NotNull(result); var receipt = await Utils.GetTransactionReceipt(contract.Client, contract.Chain, result); Assert.NotNull(receipt); @@ -108,45 +108,32 @@ public async Task WriteTest_SmartAccount() [Fact] public async Task WriteTest_PrivateKeyAccount() { - var contract = GetContract(); - var privateKeyAccount = new PrivateKeyAccount(contract.Client, _testPrivateKey); - await privateKeyAccount.Connect(); - var wallet = new ThirdwebWallet(); - await wallet.Initialize(new List { privateKeyAccount }); - var receiver = await wallet.GetAddress(); + var contract = await GetContract(); + var privateKeyAccount = await PrivateKeyAccount.Create(contract.Client, _testPrivateKey); + var receiver = await privateKeyAccount.GetAddress(); var quantity = BigInteger.One; var currency = Constants.NATIVE_TOKEN_ADDRESS; var pricePerToken = BigInteger.Zero; var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; var data = new byte[] { }; var exception = await Assert.ThrowsAsync( - async () => await ThirdwebContract.WriteContract(wallet, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data) + async () => await ThirdwebContract.Write(privateKeyAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data) ); Assert.Contains("insufficient funds", exception.Message); } - private async Task GetWallet() + private async Task GetAccount() { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - var smartAccount = new SmartAccount(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - await privateKeyAccount.Connect(); - await smartAccount.Connect(); - var wallet = new ThirdwebWallet(); - await wallet.Initialize(new List { privateKeyAccount, smartAccount }); - wallet.SetActive(await smartAccount.GetAddress()); - return wallet; + var client = ThirdwebClient.Create(secretKey: _secretKey); + var privateKeyAccount = await PrivateKeyAccount.Create(client, _testPrivateKey); + var smartAccount = await SmartAccount.Create(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + return smartAccount; } - private ThirdwebContract GetContract() + private async Task GetContract() { - var client = new ThirdwebClient(secretKey: _secretKey); - var contract = new ThirdwebContract( - client: client, - address: "0xEBB8a39D865465F289fa349A67B3391d8f910da9", - chain: 421614, - abi: "[{\"type\": \"constructor\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"event\",\"name\": \"Approval\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"spender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"value\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ClaimConditionsUpdated\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"claimConditions\",\"components\": [{\"type\": \"uint256\",\"name\": \"startTimestamp\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"maxClaimableSupply\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"supplyClaimed\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"quantityLimitPerWallet\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"merkleRoot\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"pricePerToken\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"},{\"type\": \"string\",\"name\": \"metadata\",\"internalType\": \"string\"}],\"indexed\": false,\"internalType\": \"struct IClaimCondition.ClaimCondition[]\"},{\"type\": \"bool\",\"name\": \"resetEligibility\",\"indexed\": false,\"internalType\": \"bool\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ContractURIUpdated\",\"inputs\": [{\"type\": \"string\",\"name\": \"prevURI\",\"indexed\": false,\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"newURI\",\"indexed\": false,\"internalType\": \"string\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"DelegateChanged\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegator\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"fromDelegate\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"toDelegate\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"DelegateVotesChanged\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegate\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"previousBalance\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"newBalance\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"EIP712DomainChanged\",\"inputs\": [],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FlatPlatformFeeUpdated\",\"inputs\": [{\"type\": \"address\",\"name\": \"platformFeeRecipient\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"flatFee\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Initialized\",\"inputs\": [{\"type\": \"uint8\",\"name\": \"version\",\"indexed\": false,\"internalType\": \"uint8\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"MaxTotalSupplyUpdated\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"maxTotalSupply\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PlatformFeeInfoUpdated\",\"inputs\": [{\"type\": \"address\",\"name\": \"platformFeeRecipient\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"platformFeeBps\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PlatformFeeTypeUpdated\",\"inputs\": [{\"type\": \"uint8\",\"name\": \"feeType\",\"indexed\": false,\"internalType\": \"enum IPlatformFee.PlatformFeeType\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PrimarySaleRecipientUpdated\",\"inputs\": [{\"type\": \"address\",\"name\": \"recipient\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleAdminChanged\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"previousAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"newAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleGranted\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleRevoked\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"TokensClaimed\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"claimConditionIndex\",\"indexed\": true,\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"claimer\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"receiver\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"startTokenId\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"quantityClaimed\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Transfer\",\"inputs\": [{\"type\": \"address\",\"name\": \"from\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"to\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"value\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"function\",\"name\": \"CLOCK_MODE\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"DEFAULT_ADMIN_ROLE\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"DOMAIN_SEPARATOR\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"allowance\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"approve\",\"inputs\": [{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"balanceOf\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"burn\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"burnFrom\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"checkpoints\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"},{\"type\": \"uint32\",\"name\": \"pos\",\"internalType\": \"uint32\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"uint32\",\"name\": \"fromBlock\",\"internalType\": \"uint32\"},{\"type\": \"uint224\",\"name\": \"votes\",\"internalType\": \"uint224\"}],\"internalType\": \"struct ERC20VotesUpgradeable.Checkpoint\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"claim\",\"inputs\": [{\"type\": \"address\",\"name\": \"_receiver\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_quantity\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"_currency\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_pricePerToken\",\"internalType\": \"uint256\"},{\"type\": \"tuple\",\"name\": \"_allowlistProof\",\"components\": [{\"type\": \"bytes32[]\",\"name\": \"proof\",\"internalType\": \"bytes32[]\"},{\"type\": \"uint256\",\"name\": \"quantityLimitPerWallet\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"pricePerToken\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"}],\"internalType\": \"struct IDrop.AllowlistProof\"},{\"type\": \"bytes\",\"name\": \"_data\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"claimCondition\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"currentStartId\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"count\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"clock\",\"inputs\": [],\"outputs\": [{\"type\": \"uint48\",\"name\": \"\",\"internalType\": \"uint48\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"contractType\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"pure\"},{\"type\": \"function\",\"name\": \"contractURI\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"contractVersion\",\"inputs\": [],\"outputs\": [{\"type\": \"uint8\",\"name\": \"\",\"internalType\": \"uint8\"}],\"stateMutability\": \"pure\"},{\"type\": \"function\",\"name\": \"decimals\",\"inputs\": [],\"outputs\": [{\"type\": \"uint8\",\"name\": \"\",\"internalType\": \"uint8\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"decreaseAllowance\",\"inputs\": [{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"subtractedValue\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"delegate\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegatee\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"delegateBySig\",\"inputs\": [{\"type\": \"address\",\"name\": \"delegatee\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"expiry\",\"internalType\": \"uint256\"},{\"type\": \"uint8\",\"name\": \"v\",\"internalType\": \"uint8\"},{\"type\": \"bytes32\",\"name\": \"r\",\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"s\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"delegates\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"eip712Domain\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes1\",\"name\": \"fields\",\"internalType\": \"bytes1\"},{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"version\",\"internalType\": \"string\"},{\"type\": \"uint256\",\"name\": \"chainId\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"verifyingContract\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"salt\",\"internalType\": \"bytes32\"},{\"type\": \"uint256[]\",\"name\": \"extensions\",\"internalType\": \"uint256[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getActiveClaimConditionId\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getClaimConditionById\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_conditionId\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"condition\",\"components\": [{\"type\": \"uint256\",\"name\": \"startTimestamp\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"maxClaimableSupply\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"supplyClaimed\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"quantityLimitPerWallet\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"merkleRoot\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"pricePerToken\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"},{\"type\": \"string\",\"name\": \"metadata\",\"internalType\": \"string\"}],\"internalType\": \"struct IClaimCondition.ClaimCondition\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getFlatPlatformFeeInfo\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getPastTotalSupply\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"timepoint\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getPastVotes\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"timepoint\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getPlatformFeeInfo\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"},{\"type\": \"uint16\",\"name\": \"\",\"internalType\": \"uint16\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getPlatformFeeType\",\"inputs\": [],\"outputs\": [{\"type\": \"uint8\",\"name\": \"\",\"internalType\": \"enum IPlatformFee.PlatformFeeType\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleAdmin\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMember\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"index\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"member\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMemberCount\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"count\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getSupplyClaimedByWallet\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_conditionId\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"_claimer\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"supplyClaimedByWallet\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getVotes\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"grantRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"hasRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"hasRoleWithSwitch\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"increaseAllowance\",\"inputs\": [{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"addedValue\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"initialize\",\"inputs\": [{\"type\": \"address\",\"name\": \"_defaultAdmin\",\"internalType\": \"address\"},{\"type\": \"string\",\"name\": \"_name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"_symbol\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"_contractURI\",\"internalType\": \"string\"},{\"type\": \"address[]\",\"name\": \"_trustedForwarders\",\"internalType\": \"address[]\"},{\"type\": \"address\",\"name\": \"_saleRecipient\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"_platformFeeRecipient\",\"internalType\": \"address\"},{\"type\": \"uint128\",\"name\": \"_platformFeeBps\",\"internalType\": \"uint128\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"isTrustedForwarder\",\"inputs\": [{\"type\": \"address\",\"name\": \"forwarder\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"maxTotalSupply\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"multicall\",\"inputs\": [{\"type\": \"bytes[]\",\"name\": \"data\",\"internalType\": \"bytes[]\"}],\"outputs\": [{\"type\": \"bytes[]\",\"name\": \"results\",\"internalType\": \"bytes[]\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"name\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"nonces\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"numCheckpoints\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint32\",\"name\": \"\",\"internalType\": \"uint32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"permit\",\"inputs\": [{\"type\": \"address\",\"name\": \"owner\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"spender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"value\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"deadline\",\"internalType\": \"uint256\"},{\"type\": \"uint8\",\"name\": \"v\",\"internalType\": \"uint8\"},{\"type\": \"bytes32\",\"name\": \"r\",\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"s\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"primarySaleRecipient\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"renounceRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"revokeRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setClaimConditions\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"_conditions\",\"components\": [{\"type\": \"uint256\",\"name\": \"startTimestamp\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"maxClaimableSupply\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"supplyClaimed\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"quantityLimitPerWallet\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"merkleRoot\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"pricePerToken\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"},{\"type\": \"string\",\"name\": \"metadata\",\"internalType\": \"string\"}],\"internalType\": \"struct IClaimCondition.ClaimCondition[]\"},{\"type\": \"bool\",\"name\": \"_resetClaimEligibility\",\"internalType\": \"bool\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setContractURI\",\"inputs\": [{\"type\": \"string\",\"name\": \"_uri\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setFlatPlatformFeeInfo\",\"inputs\": [{\"type\": \"address\",\"name\": \"_platformFeeRecipient\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_flatFee\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setMaxTotalSupply\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_maxTotalSupply\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setPlatformFeeInfo\",\"inputs\": [{\"type\": \"address\",\"name\": \"_platformFeeRecipient\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_platformFeeBps\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setPlatformFeeType\",\"inputs\": [{\"type\": \"uint8\",\"name\": \"_feeType\",\"internalType\": \"enum IPlatformFee.PlatformFeeType\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setPrimarySaleRecipient\",\"inputs\": [{\"type\": \"address\",\"name\": \"_saleRecipient\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"symbol\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"totalSupply\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"transfer\",\"inputs\": [{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"transferFrom\",\"inputs\": [{\"type\": \"address\",\"name\": \"from\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"to\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"verifyClaim\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_conditionId\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"_claimer\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_quantity\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"_currency\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"_pricePerToken\",\"internalType\": \"uint256\"},{\"type\": \"tuple\",\"name\": \"_allowlistProof\",\"components\": [{\"type\": \"bytes32[]\",\"name\": \"proof\",\"internalType\": \"bytes32[]\"},{\"type\": \"uint256\",\"name\": \"quantityLimitPerWallet\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"pricePerToken\",\"internalType\": \"uint256\"},{\"type\": \"address\",\"name\": \"currency\",\"internalType\": \"address\"}],\"internalType\": \"struct IDrop.AllowlistProof\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"isOverride\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"}]" - ); + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client: client, address: "0xEBB8a39D865465F289fa349A67B3391d8f910da9", chain: 421614); return contract; } } diff --git a/Thirdweb.Tests/Thirdweb.PrivateKeyAccount.Tests.cs b/Thirdweb.Tests/Thirdweb.PrivateKeyAccount.Tests.cs index 3a69189..4f4b7d1 100644 --- a/Thirdweb.Tests/Thirdweb.PrivateKeyAccount.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.PrivateKeyAccount.Tests.cs @@ -9,41 +9,39 @@ public class PrivateKeyAccountTests : BaseTests public PrivateKeyAccountTests(ITestOutputHelper output) : base(output) { } - private PrivateKeyAccount GetAccount() + private async Task GetAccount() { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client: client, privateKeyHex: _testPrivateKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); + var privateKeyAccount = await PrivateKeyAccount.Create(client: client, privateKeyHex: _testPrivateKey); return privateKeyAccount; } [Fact] - public void Initialization_Success() + public async Task Initialization_Success() { - var account = GetAccount(); + var account = await GetAccount(); Assert.NotNull(account); } [Fact] - public void Initialization_NullPrivateKey() + public async void Initialization_NullPrivateKey() { - var client = new ThirdwebClient(secretKey: _secretKey); - var ex = Assert.Throws(() => new PrivateKeyAccount(client, null)); + var client = ThirdwebClient.Create(secretKey: _secretKey); + var ex = await Assert.ThrowsAsync(async () => await PrivateKeyAccount.Create(client, null)); Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); } [Fact] public async Task Connect() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); Assert.True(await account.IsConnected()); } [Fact] public async Task GetAddress() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var address = await account.GetAddress(); Assert.True(address.Length == 42); } @@ -51,8 +49,7 @@ public async Task GetAddress() [Fact] public async Task EthSign_Success() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var message = "Hello, World!"; var signature = await account.EthSign(message); Assert.True(signature.Length == 132); @@ -61,8 +58,7 @@ public async Task EthSign_Success() [Fact] public async Task EthSign_NullMessage() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var ex = await Assert.ThrowsAsync(() => account.EthSign(null)); Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } @@ -70,8 +66,7 @@ public async Task EthSign_NullMessage() [Fact] public async Task PersonalSign_Success() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var message = "Hello, World!"; var signature = await account.PersonalSign(message); Assert.True(signature.Length == 132); @@ -80,8 +75,7 @@ public async Task PersonalSign_Success() [Fact] public async Task PersonalSign_EmptyMessage() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var ex = await Assert.ThrowsAsync(() => account.PersonalSign(string.Empty)); Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } @@ -89,8 +83,8 @@ public async Task PersonalSign_EmptyMessage() [Fact] public async Task PersonalSign_NullyMessage() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); + var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as string)); Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } @@ -98,8 +92,7 @@ public async Task PersonalSign_NullyMessage() [Fact] public async Task PersonalSignRaw_Success() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var message = System.Text.Encoding.UTF8.GetBytes("Hello, World!"); var signature = await account.PersonalSign(message); Assert.True(signature.Length == 132); @@ -108,8 +101,7 @@ public async Task PersonalSignRaw_Success() [Fact] public async Task PersonalSignRaw_NullMessage() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as byte[])); Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); } @@ -117,8 +109,7 @@ public async Task PersonalSignRaw_NullMessage() [Fact] public async Task SignTypedDataV4_Success() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var json = "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; var signature = await account.SignTypedDataV4(json); @@ -128,8 +119,7 @@ public async Task SignTypedDataV4_Success() [Fact] public async Task SignTypedDataV4_NullJson() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(null)); Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); } @@ -137,8 +127,7 @@ public async Task SignTypedDataV4_NullJson() [Fact] public async Task SignTypedDataV4_EmptyJson() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(string.Empty)); Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); } @@ -146,8 +135,7 @@ public async Task SignTypedDataV4_EmptyJson() [Fact] public async Task SignTypedDataV4_Typed() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var typedData = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 421614, await account.GetAddress()); var accountMessage = new AccountAbstraction.AccountMessage { Message = System.Text.Encoding.UTF8.GetBytes("Hello, world!") }; var signature = await account.SignTypedDataV4(accountMessage, typedData); @@ -157,8 +145,7 @@ public async Task SignTypedDataV4_Typed() [Fact] public async Task SignTypedDataV4_Typed_NullData() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var typedData = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 421614, await account.GetAddress()); var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(null as string, typedData)); Assert.Equal("Data to sign cannot be null. (Parameter 'data')", ex.Message); @@ -167,8 +154,7 @@ public async Task SignTypedDataV4_Typed_NullData() [Fact] public async Task SignTransaction_Success() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var transaction = new TransactionInput { From = await account.GetAddress(), @@ -186,8 +172,7 @@ public async Task SignTransaction_Success() [Fact] public async Task SignTransaction_NullTransaction() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var ex = await Assert.ThrowsAsync(() => account.SignTransaction(null, 421614)); Assert.Equal("Value cannot be null. (Parameter 'transaction')", ex.Message); } @@ -195,8 +180,7 @@ public async Task SignTransaction_NullTransaction() [Fact] public async Task SignTransaction_NoNonce() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var transaction = new TransactionInput { From = await account.GetAddress(), @@ -212,8 +196,7 @@ public async Task SignTransaction_NoNonce() [Fact] public async Task SignTransaction_WrongFrom() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var transaction = new TransactionInput { From = Constants.ADDRESS_ZERO, @@ -230,8 +213,7 @@ public async Task SignTransaction_WrongFrom() [Fact] public async Task SignTransaction_NoGasPrice() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var transaction = new TransactionInput { From = await account.GetAddress(), @@ -248,8 +230,7 @@ public async Task SignTransaction_NoGasPrice() [Fact] public async Task SignTransaction_1559_Success() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var transaction = new TransactionInput { From = await account.GetAddress(), @@ -269,8 +250,7 @@ public async Task SignTransaction_1559_Success() [Fact] public async Task SignTransaction_1559_NoMaxFeePerGas() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var transaction = new TransactionInput { From = await account.GetAddress(), @@ -289,8 +269,7 @@ public async Task SignTransaction_1559_NoMaxFeePerGas() [Fact] public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); var transaction = new TransactionInput { From = await account.GetAddress(), @@ -309,23 +288,22 @@ public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() [Fact] public async Task IsConnected_True() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); Assert.True(await account.IsConnected()); } [Fact] public async Task IsConnected_False() { - var account = GetAccount(); + var account = await GetAccount(); + await account.Disconnect(); Assert.False(await account.IsConnected()); } [Fact] public async Task Disconnect() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } @@ -333,7 +311,7 @@ public async Task Disconnect() [Fact] public async Task Disconnect_NotConnected() { - var account = GetAccount(); + var account = await GetAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } @@ -341,8 +319,7 @@ public async Task Disconnect_NotConnected() [Fact] public async Task Disconnect_Connected() { - var account = GetAccount(); - await account.Connect(); + var account = await GetAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } diff --git a/Thirdweb.Tests/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC.Tests.cs index 462de40..a4d109a 100644 --- a/Thirdweb.Tests/Thirdweb.RPC.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.RPC.Tests.cs @@ -10,7 +10,7 @@ public RpcTests(ITestOutputHelper output) [Fact] public async Task GetBlockNumber() { - var client = new ThirdwebClient(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 10000)); + var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 10000)); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); Assert.NotNull(blockNumber); @@ -20,7 +20,7 @@ public async Task GetBlockNumber() [Fact] public async Task TestAuth() { - var client = new ThirdwebClient(clientId: "hi", fetchTimeoutOptions: new TimeoutOptions(rpc: 60000)); + var client = ThirdwebClient.Create(clientId: "hi", fetchTimeoutOptions: new TimeoutOptions(rpc: 60000)); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); _output.WriteLine($"TestAuth Exception Message: {exception.Message}"); @@ -29,7 +29,7 @@ public async Task TestAuth() [Fact] public async Task TestTimeout() { - var client = new ThirdwebClient(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 0)); + var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 0)); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_chainId")); _output.WriteLine($"TestTimeout Exception Message: {exception.Message}"); @@ -38,7 +38,7 @@ public async Task TestTimeout() [Fact] public async Task TestBatch() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var req = rpc.SendRequestAsync("eth_blockNumber"); _ = await rpc.SendRequestAsync("eth_chainId"); @@ -56,7 +56,7 @@ public async Task TestBatch() [Fact] public async Task TestDeserialization() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); Assert.Equal("Failed to deserialize RPC response.", exception.Message); @@ -67,14 +67,14 @@ public void TestBadInitialization() { var clientException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(null, 0)); Assert.Equal("client", clientException.ParamName); - var chainIdException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(new ThirdwebClient(secretKey: _secretKey), 0)); + var chainIdException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: _secretKey), 0)); Assert.Equal("Invalid Chain ID", chainIdException.Message); } [Fact] public async Task TestBundleIdRpc() { - var client = new ThirdwebClient(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); Assert.NotNull(blockNumber); @@ -84,7 +84,7 @@ public async Task TestBundleIdRpc() [Fact] public async Task TestRpcError() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_invalidMethod")); Assert.Contains("RPC Error for request", exception.Message); diff --git a/Thirdweb.Tests/Thirdweb.SmartAccount.Tests.cs b/Thirdweb.Tests/Thirdweb.SmartAccount.Tests.cs index 4d2c508..14f01e2 100644 --- a/Thirdweb.Tests/Thirdweb.SmartAccount.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.SmartAccount.Tests.cs @@ -11,11 +11,9 @@ public SmartAccountTests(ITestOutputHelper output) private async Task GetSmartAccount() { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - await privateKeyAccount.Connect(); - var smartAccount = new SmartAccount(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - await smartAccount.Connect(); + var client = ThirdwebClient.Create(secretKey: _secretKey); + var privateKeyAccount = await PrivateKeyAccount.Create(client, _testPrivateKey); + var smartAccount = await SmartAccount.Create(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); return smartAccount; } @@ -29,10 +27,12 @@ public async Task Initialization_Success() [Fact] public async Task Initialization_Fail() { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - var smartAccount = new SmartAccount(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var ex = await Assert.ThrowsAsync(smartAccount.Connect); + var client = ThirdwebClient.Create(secretKey: _secretKey); + var privateKeyAccount = await PrivateKeyAccount.Create(client, _testPrivateKey); + await privateKeyAccount.Disconnect(); + var ex = await Assert.ThrowsAsync( + async () => await SmartAccount.Create(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614) + ); Assert.Equal("SmartAccount.Connect: Personal account must be connected.", ex.Message); } @@ -46,10 +46,9 @@ public async Task IsDeployed_True() [Fact] public async Task IsDeployed_False() { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - await privateKeyAccount.Connect(); - var smartAccount = new SmartAccount( + var client = ThirdwebClient.Create(secretKey: _secretKey); + var privateKeyAccount = await PrivateKeyAccount.Create(client, _testPrivateKey); + var smartAccount = await SmartAccount.Create( client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", @@ -57,7 +56,6 @@ public async Task IsDeployed_False() chainId: 421614, accountAddressOverride: "0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642" // vanity ); - await smartAccount.Connect(); Assert.False(await smartAccount.IsDeployed()); } @@ -79,11 +77,9 @@ public async Task SendTransaction_Success() [Fact] public async Task SendTransaction_ClientBundleId_Success() { - var client = new ThirdwebClient(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - await privateKeyAccount.Connect(); - var smartAccount = new SmartAccount(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - await smartAccount.Connect(); + var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var privateKeyAccount = await PrivateKeyAccount.Create(client, _testPrivateKey); + var smartAccount = await SmartAccount.Create(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); var tx = await smartAccount.SendTransaction( new TransactionInput() { @@ -123,10 +119,9 @@ public async Task GetPersonalAccount() [Fact] public async Task GetAddress_WithOverride() { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - await privateKeyAccount.Connect(); - var smartAccount = new SmartAccount( + var client = ThirdwebClient.Create(secretKey: _secretKey); + var privateKeyAccount = await PrivateKeyAccount.Create(client, _testPrivateKey); + var smartAccount = await SmartAccount.Create( client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", @@ -134,7 +129,6 @@ public async Task GetAddress_WithOverride() chainId: 421614, accountAddressOverride: "0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642" // vanity ); - await smartAccount.Connect(); var address = await smartAccount.GetAddress(); Assert.Equal("0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642", address); } @@ -147,6 +141,17 @@ public async Task GetAddress_WithOverride() Assert.NotNull(sig); } + [Fact] + public async Task IsValidSiganture_Invalid() + { + var account = await GetSmartAccount(); + var sig = await account.PersonalSign("Hello, world!"); + Assert.NotNull(sig); + sig += "1"; + var res = await account.IsValidSignature("Hello, world!", sig); + Assert.False(res); + } + [Fact] public async Task CreateSessionKey() { diff --git a/Thirdweb.Tests/Thirdweb.Storage.Tests.cs b/Thirdweb.Tests/Thirdweb.Storage.Tests.cs index 0a9a3c6..297ebf3 100644 --- a/Thirdweb.Tests/Thirdweb.Storage.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Storage.Tests.cs @@ -8,7 +8,7 @@ public StorageTests(ITestOutputHelper output) [Fact] public async Task DownloadTest_SecretKey() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); Assert.NotNull(res); } @@ -16,7 +16,7 @@ public async Task DownloadTest_SecretKey() [Fact] public async Task DownloadTest_Client_BundleId() { - var client = new ThirdwebClient(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); Assert.NotNull(res); } @@ -24,7 +24,7 @@ public async Task DownloadTest_Client_BundleId() [Fact] public async Task DownloadTest_Deserialization() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var res = await ThirdwebStorage.Download>(client, "https://1.rpc.thirdweb.com/providers"); Assert.NotNull(res); Assert.NotEmpty(res); @@ -33,7 +33,7 @@ public async Task DownloadTest_Deserialization() [Fact] public async Task DownloadTest_NullUri() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, null)); Assert.Equal("uri", exception.ParamName); } @@ -41,7 +41,7 @@ public async Task DownloadTest_NullUri() [Fact] public async Task DownloadTest_ThirdwebIPFS() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var res = await ThirdwebStorage.Download(client, "ipfs://QmRHf3sBEAaSkaPdjrnYZS7VH1jVgvNBJNoUXmiUyvUpNM/8"); Assert.NotNull(res); } @@ -49,7 +49,7 @@ public async Task DownloadTest_ThirdwebIPFS() [Fact] public async Task DownloadTest_400() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://0.rpc.thirdweb.com/")); Assert.Contains("Failed to download", exception.Message); Assert.Contains("BadRequest", exception.Message); @@ -58,7 +58,7 @@ public async Task DownloadTest_400() [Fact] public async Task DownloadTest_Timeout() { - var client = new ThirdwebClient(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 0)); + var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 0)); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers", 1)); Assert.Contains("A task was canceled", exception.Message); } @@ -66,7 +66,7 @@ public async Task DownloadTest_Timeout() [Fact] public async Task UploadTest_SecretKey() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var path = Path.Combine(Path.GetTempPath(), "testJson.json"); File.WriteAllText(path, "{\"test\": \"test\"}"); var res = await ThirdwebStorage.Upload(client, path); @@ -76,7 +76,7 @@ public async Task UploadTest_SecretKey() [Fact] public async Task UploadTest_Client_BundleId() { - var client = new ThirdwebClient(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); var path = Path.Combine(Path.GetTempPath(), "testJson.json"); File.WriteAllText(path, "{\"test\": \"test\"}"); var res = await ThirdwebStorage.Upload(client, path); @@ -86,7 +86,7 @@ public async Task UploadTest_Client_BundleId() [Fact] public async Task UploadTest_NullPath() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, null)); Assert.Equal("path", exception.ParamName); } @@ -94,7 +94,7 @@ public async Task UploadTest_NullPath() [Fact] public async Task UploadTest_401() { - var client = new ThirdwebClient(clientId: "invalid", bundleId: "hello"); + var client = ThirdwebClient.Create(clientId: "invalid", bundleId: "hello"); var path = Path.Combine(Path.GetTempPath(), "testJson.json"); File.WriteAllText(path, "{\"test\": \"test\"}"); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, path)); diff --git a/Thirdweb.Tests/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils.Tests.cs index cbe9e54..01f5fa8 100644 --- a/Thirdweb.Tests/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils.Tests.cs @@ -21,7 +21,7 @@ public void HexConcat() [Fact] public async Task GetTransactionReceipt() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var chainId = 421614; var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; @@ -44,7 +44,7 @@ public async Task GetTransactionReceipt() [Fact] public async Task GetTransactionReceipt_AAReasonString() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var chainId = 84532; var aaSilentRevertTxHashWithReason = "0x5374743bbb749df47a279ac21e6ed472c30cd471923a7bc78db6a40e1b6924de"; var aaFailedReceiptWithReason = await Assert.ThrowsAsync(async () => await Utils.GetTransactionReceipt(client, chainId, aaSilentRevertTxHashWithReason)); @@ -54,7 +54,7 @@ public async Task GetTransactionReceipt_AAReasonString() [Fact] public async Task GetTransactionReceipt_CancellationToken() { - var client = new ThirdwebClient(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: _secretKey); var chainId = 421614; var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; diff --git a/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs index f103573..28a79ef 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs @@ -8,83 +8,43 @@ public class WalletTests : BaseTests public WalletTests(ITestOutputHelper output) : base(output) { } - private async Task GetWallet() + private async Task GetAccount() { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - var smartAccount = new SmartAccount(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - await privateKeyAccount.Connect(); - await smartAccount.Connect(); - var wallet = new ThirdwebWallet(); - await wallet.Initialize(new List { privateKeyAccount, smartAccount }); - wallet.SetActive(await smartAccount.GetAddress()); - return wallet; + var client = ThirdwebClient.Create(secretKey: _secretKey); + var privateKeyAccount = await PrivateKeyAccount.Create(client, _testPrivateKey); + var smartAccount = await SmartAccount.Create(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + return smartAccount; } [Fact] - public async Task Initialization_Success() - { - var wallet = await GetWallet(); - Assert.NotNull(wallet.ActiveAccount); - Assert.Equal(2, wallet.Accounts.Count); - } - - [Fact] - public async Task Initialization_NoAccounts() - { - var wallet = new ThirdwebWallet(); - var ex = await Assert.ThrowsAsync(async () => await wallet.Initialize(new List())); - Assert.Equal("At least one account must be provided.", ex.Message); - } - - [Fact] - public async Task Initialization_OneDisconnectedAccount() - { - var client = new ThirdwebClient(secretKey: _secretKey); - var privateKeyAccount = new PrivateKeyAccount(client, _testPrivateKey); - var smartAccount = new SmartAccount(client, personalAccount: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - await privateKeyAccount.Connect(); - var wallet = new ThirdwebWallet(); - var ex = await Assert.ThrowsAsync(async () => await wallet.Initialize(new List { privateKeyAccount, smartAccount })); - Assert.Equal("Account at index 1 is not connected.", ex.Message); - } - - [Fact] - public async Task SetActive_Success() - { - var wallet = await GetWallet(); - wallet.SetActive(wallet.Accounts.Keys.Last()); - Assert.Equal(wallet.Accounts.Keys.Last(), await wallet.GetAddress()); - } - - [Fact] - public async Task SetActive_NotFound() + public async Task GetAddress() { - var wallet = await GetWallet(); - var ex = Assert.Throws(() => wallet.SetActive(Constants.ADDRESS_ZERO)); - Assert.Equal($"Account with address {Constants.ADDRESS_ZERO} not found.", ex.Message); + var wallet = await GetAccount(); + Assert.Equal(await wallet.GetAddress(), await wallet.GetAddress()); } [Fact] - public async Task GetAddress() + public async Task EthSign() { - var wallet = await GetWallet(); - Assert.Equal(await wallet.ActiveAccount.GetAddress(), await wallet.GetAddress()); + var wallet = await GetAccount(); + var message = "Hello, world!"; + var signature = await wallet.EthSign(message); + Assert.NotNull(signature); } [Fact] - public async Task EthSign() + public async Task PersonalSignRaw() { - var wallet = await GetWallet(); + var wallet = await GetAccount(); var message = "Hello, world!"; - var signature = await wallet.EthSign(message); + var signature = await wallet.PersonalSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.NotNull(signature); } [Fact] public async Task PersonalSign() { - var wallet = await GetWallet(); + var wallet = await GetAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); Assert.NotNull(signature); @@ -93,7 +53,7 @@ public async Task PersonalSign() [Fact] public async Task SignTypedDataV4() { - var wallet = await GetWallet(); + var wallet = await GetAccount(); var json = "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; var signature = await wallet.SignTypedDataV4(json); @@ -103,13 +63,13 @@ public async Task SignTypedDataV4() [Fact] public async Task SignTypedDataV4_Typed() { - var wallet = await GetWallet(); + var wallet = await GetAccount(); var typedData = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 421614, await wallet.GetAddress()); var accountMessage = new AccountAbstraction.AccountMessage { Message = System.Text.Encoding.UTF8.GetBytes("Hello, world!").HashPrefixedMessage() }; var signature = await wallet.SignTypedDataV4(accountMessage, typedData); Assert.NotNull(signature); - var signerAcc = await ((SmartAccount)wallet.ActiveAccount).GetPersonalAccount(); + var signerAcc = await (wallet).GetPersonalAccount(); var gen1 = await EIP712.GenerateSignature_SmartAccount_AccountMessage( "Account", "1", @@ -143,7 +103,7 @@ await wallet.GetAddress(), [Fact] public async Task SignTransaction() { - var wallet = await GetWallet(); + var wallet = await GetAccount(); var transaction = new TransactionInput { To = await wallet.GetAddress(), @@ -153,26 +113,8 @@ public async Task SignTransaction() GasPrice = new HexBigInteger(10000000000), Nonce = new HexBigInteger(9999999999999), }; - var rpc = ThirdwebRPC.GetRpcInstance(new ThirdwebClient(secretKey: _secretKey), 421614); + var rpc = ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: _secretKey), 421614); var signature = await wallet.SignTransaction(transaction, 421614); Assert.NotNull(signature); } - - [Fact] - public async Task IsConnected() - { - var wallet = await GetWallet(); - Assert.True(await wallet.IsConnected()); - foreach (var account in wallet.Accounts.Values) - { - Assert.True(await account.IsConnected()); - } - - await wallet.DisconnectAll(); - Assert.False(await wallet.IsConnected()); - foreach (var account in wallet.Accounts.Values) - { - Assert.False(await account.IsConnected()); - } - } } diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs index 6cefd7c..6294d49 100644 --- a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs @@ -1,5 +1,4 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Console")] namespace Thirdweb { @@ -10,7 +9,7 @@ public class ThirdwebClient internal string BundleId { get; } internal ITimeoutOptions FetchTimeoutOptions { get; } - public ThirdwebClient(string clientId = null, string secretKey = null, string bundleId = null, ITimeoutOptions fetchTimeoutOptions = null) + private ThirdwebClient(string clientId = null, string secretKey = null, string bundleId = null, ITimeoutOptions fetchTimeoutOptions = null) { if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(secretKey)) { @@ -31,5 +30,10 @@ public ThirdwebClient(string clientId = null, string secretKey = null, string bu FetchTimeoutOptions = fetchTimeoutOptions ?? new TimeoutOptions(); } + + public static ThirdwebClient Create(string clientId = null, string secretKey = null, string bundleId = null, ITimeoutOptions fetchTimeoutOptions = null) + { + return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions); + } } } diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 50f147e..48c92c2 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -1,8 +1,6 @@ using System.Numerics; using Nethereum.Hex.HexTypes; -using Nethereum.Model; using Nethereum.RPC.Eth.DTOs; -using Org.BouncyCastle.Utilities.Encoders; namespace Thirdweb { @@ -13,7 +11,15 @@ public class ThirdwebContract internal BigInteger Chain { get; private set; } internal string Abi { get; private set; } - public ThirdwebContract(ThirdwebClient client, string address, BigInteger chain, string abi) + private ThirdwebContract(ThirdwebClient client, string address, BigInteger chain, string abi) + { + Client = client; + Address = address; + Chain = chain; + Abi = abi; + } + + public static async Task Create(ThirdwebClient client, string address, BigInteger chain, string abi = null) { if (client == null) { @@ -30,15 +36,8 @@ public ThirdwebContract(ThirdwebClient client, string address, BigInteger chain, throw new ArgumentException("Chain must be provided"); } - if (string.IsNullOrEmpty(abi)) - { - throw new ArgumentException("Abi must be provided"); - } - - Client = client; - Address = address; - Chain = chain; - Abi = abi; + abi ??= await FetchAbi(address, chain); + return new ThirdwebContract(client, address, chain, abi); } public static async Task FetchAbi(string address, BigInteger chainId) @@ -52,7 +51,7 @@ public static async Task FetchAbi(string address, BigInteger chainId) } } - public static async Task ReadContract(ThirdwebContract contract, string method, params object[] parameters) + public static async Task Read(ThirdwebContract contract, string method, params object[] parameters) { var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); @@ -64,7 +63,7 @@ public static async Task ReadContract(ThirdwebContract contract, string me return function.DecodeTypeOutput(resultData); } - public static async Task WriteContract(ThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + public static async Task Write(IThirdwebAccount account, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) { var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); @@ -74,7 +73,7 @@ public static async Task WriteContract(ThirdwebWallet wallet, ThirdwebCo var transaction = new TransactionInput { - From = await wallet.GetAddress(), + From = await account.GetAddress(), To = contract.Address, Data = data, }; @@ -86,15 +85,15 @@ public static async Task WriteContract(ThirdwebWallet wallet, ThirdwebCo transaction.Value = new HexBigInteger(weiValue); string hash; - switch (wallet.ActiveAccount.AccountType) + switch (account.AccountType) { case ThirdwebAccountType.PrivateKeyAccount: - transaction.Nonce = new HexBigInteger(await rpc.SendRequestAsync("eth_getTransactionCount", await wallet.GetAddress(), "latest")); - var signedTx = await wallet.SignTransaction(transaction, contract.Chain); + transaction.Nonce = new HexBigInteger(await rpc.SendRequestAsync("eth_getTransactionCount", await account.GetAddress(), "latest")); + var signedTx = await account.SignTransaction(transaction, contract.Chain); hash = await rpc.SendRequestAsync("eth_sendRawTransaction", signedTx); break; case ThirdwebAccountType.SmartAccount: - var smartAccount = wallet.ActiveAccount as SmartAccount; + var smartAccount = account as SmartAccount; hash = await smartAccount.SendTransaction(transaction); break; default: diff --git a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs index 47f4906..1240bec 100644 --- a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs +++ b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs @@ -2,7 +2,7 @@ namespace Thirdweb { - public class ThirdwebStorage + public static class ThirdwebStorage { public static async Task Download(ThirdwebClient client, string uri, int? requestTimeout = null) { diff --git a/Thirdweb/Thirdweb.Wallets/EmbeddedAccount/EmbeddedAccount.cs b/Thirdweb/Thirdweb.Wallets/EmbeddedAccount/EmbeddedAccount.cs index 4deb193..c8c5498 100644 --- a/Thirdweb/Thirdweb.Wallets/EmbeddedAccount/EmbeddedAccount.cs +++ b/Thirdweb/Thirdweb.Wallets/EmbeddedAccount/EmbeddedAccount.cs @@ -12,43 +12,40 @@ namespace Thirdweb { - public class EmbeddedAccount : IThirdwebAccount + public class EmbeddedAccount : PrivateKeyAccount { - public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; + internal EmbeddedWallet _embeddedWallet; + internal string _email; + internal string _phoneNumber; - private ThirdwebClient _client; - private EmbeddedWallet _embeddedWallet; - private User _user; - private EthECKey _ecKey; - private string _email; - private string _phoneNumber; + internal EmbeddedAccount(ThirdwebClient client, string email, string phoneNumber, EmbeddedWallet embeddedWallet, EthECKey ecKey) + : base(client, ecKey) + { + _email = email; + _phoneNumber = phoneNumber; + _embeddedWallet = embeddedWallet; + } - public EmbeddedAccount(ThirdwebClient client, string email = null, string phoneNumber = null) + public static async Task Create(ThirdwebClient client, string email = null, string phoneNumber = null) { if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber)) { throw new ArgumentException("Email or Phone Number must be provided to login."); } - _embeddedWallet = new EmbeddedWallet(client); - _email = email; - _phoneNumber = phoneNumber; - _client = client; - } - - public async Task Connect() - { + var embeddedWallet = new EmbeddedWallet(client); + EthECKey ecKey; try { - _user = await _embeddedWallet.GetUserAsync(_email, _email == null ? "PhoneOTP" : "EmailOTP"); - _ecKey = new EthECKey(_user.Account.PrivateKey); + var user = await embeddedWallet.GetUserAsync(email, email == null ? "PhoneOTP" : "EmailOTP"); + ecKey = new EthECKey(user.Account.PrivateKey); } catch { Console.WriteLine("User not found. Please call EmbeddedAccount.SendOTP() to initialize the login process."); - _user = null; - _ecKey = null; + ecKey = null; } + return new EmbeddedAccount(client, email, phoneNumber, embeddedWallet, ecKey); } #region OTP Flow @@ -111,8 +108,7 @@ public async Task SendOTP() } else { - _user = res.User; - _ecKey = new EthECKey(_user.Account.PrivateKey); + _ecKey = new EthECKey(res.User.Account.PrivateKey); return (await GetAddress(), false); } } @@ -128,142 +124,5 @@ public Task GetPhoneNumber() } #endregion - - public Task GetAddress() - { - return Task.FromResult(_ecKey.GetPublicAddress()); - } - - public Task EthSign(string message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - var signer = new MessageSigner(); - var signature = signer.Sign(Encoding.UTF8.GetBytes(message), _ecKey); - return Task.FromResult(signature); - } - - public Task PersonalSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var signature = signer.Sign(rawMessage, _ecKey); - return Task.FromResult(signature); - } - - public Task PersonalSign(string message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var signature = signer.EncodeUTF8AndSign(message, _ecKey); - return Task.FromResult(signature); - } - - public Task SignTypedDataV4(string json) - { - if (json == null) - { - throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var signature = signer.SignTypedDataV4(json, _ecKey); - return Task.FromResult(signature); - } - - public Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var signature = signer.SignTypedDataV4(data, typedData, _ecKey); - return Task.FromResult(signature); - } - - public async Task SignTransaction(TransactionInput transaction, BigInteger chainId) - { - if (transaction == null) - { - throw new ArgumentNullException(nameof(transaction)); - } - - if (string.IsNullOrWhiteSpace(transaction.From)) - { - transaction.From = await GetAddress(); - } - else if (transaction.From != await GetAddress()) - { - throw new Exception("Transaction 'From' address does not match the wallet address"); - } - - var nonce = transaction.Nonce ?? throw new ArgumentNullException(nameof(transaction), "Transaction nonce has not been set"); - - var gasLimit = transaction.Gas; - var value = transaction.Value ?? new HexBigInteger(0); - - string signedTransaction; - if (transaction.Type != null && transaction.Type.Value == TransactionType.EIP1559.AsByte()) - { - var maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas.Value; - var maxFeePerGas = transaction.MaxFeePerGas.Value; - var transaction1559 = new Transaction1559( - chainId, - nonce, - maxPriorityFeePerGas, - maxFeePerGas, - gasLimit, - transaction.To, - value, - transaction.Data, - transaction.AccessList.ToSignerAccessListItemArray() - ); - - var signer = new Transaction1559Signer(); - signer.SignTransaction(_ecKey, transaction1559); - signedTransaction = transaction1559.GetRLPEncoded().ToHex(); - } - else - { - var gasPrice = transaction.GasPrice; - var legacySigner = new LegacyTransactionSigner(); - signedTransaction = legacySigner.SignTransaction(_ecKey.GetPrivateKey(), chainId, transaction.To, value.Value, nonce, gasPrice.Value, gasLimit.Value, transaction.Data); - } - - return "0x" + signedTransaction; - } - - public Task IsConnected() - { - return Task.FromResult(_ecKey != null); - } - - public async Task Disconnect() - { - try - { - await _embeddedWallet.SignOutAsync(); - } - catch - { - Console.WriteLine("Failed to sign out user. Proceeding anyway."); - } - _user = null; - _ecKey = null; - } } } diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebAccount.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebAccount.cs index 6d2c7f6..2ea5ef5 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebAccount.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebAccount.cs @@ -7,7 +7,6 @@ namespace Thirdweb public interface IThirdwebAccount { public ThirdwebAccountType AccountType { get; } - public Task Connect(); public Task GetAddress(); public Task EthSign(string message); public Task PersonalSign(byte[] rawMessage); @@ -15,9 +14,8 @@ public interface IThirdwebAccount public Task SignTypedDataV4(string json); public Task SignTypedDataV4(T data, TypedData typedData) where TDomain : IDomain; - public Task SignTransaction(TransactionInput transaction, BigInteger chainId); public Task IsConnected(); - public Task Disconnect(); + public Task SignTransaction(TransactionInput transaction, BigInteger chainId); } public enum ThirdwebAccountType diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyAccount/PrivateKeyAccount.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyAccount/PrivateKeyAccount.cs index 4fa9b7d..bd5e921 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyAccount/PrivateKeyAccount.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyAccount/PrivateKeyAccount.cs @@ -15,34 +15,28 @@ public class PrivateKeyAccount : IThirdwebAccount { public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; - private ThirdwebClient _client; - private EthECKey _ecKey; - private string _privateKeyHex; + protected ThirdwebClient _client; + protected EthECKey _ecKey; - public PrivateKeyAccount(ThirdwebClient client, string privateKeyHex) + protected PrivateKeyAccount(ThirdwebClient client, EthECKey key) { - if (string.IsNullOrEmpty(privateKeyHex)) - { - throw new ArgumentNullException(nameof(privateKeyHex), "Private key cannot be null or empty."); - } - _client = client; - _privateKeyHex = privateKeyHex; + _ecKey = key; } - public Task Connect() + public static Task Create(ThirdwebClient client, string privateKeyHex) { - _ecKey = new EthECKey(_privateKeyHex); - _privateKeyHex = null; - return Task.CompletedTask; + return string.IsNullOrEmpty(privateKeyHex) + ? throw new ArgumentNullException(nameof(privateKeyHex), "Private key cannot be null or empty.") + : Task.FromResult(new PrivateKeyAccount(client, new EthECKey(privateKeyHex))); } - public Task GetAddress() + public virtual Task GetAddress() { return Task.FromResult(_ecKey.GetPublicAddress()); } - public Task EthSign(string message) + public virtual Task EthSign(string message) { if (message == null) { @@ -54,7 +48,7 @@ public Task EthSign(string message) return Task.FromResult(signature); } - public Task PersonalSign(byte[] rawMessage) + public virtual Task PersonalSign(byte[] rawMessage) { if (rawMessage == null) { @@ -66,7 +60,7 @@ public Task PersonalSign(byte[] rawMessage) return Task.FromResult(signature); } - public Task PersonalSign(string message) + public virtual Task PersonalSign(string message) { if (string.IsNullOrEmpty(message)) { @@ -78,7 +72,7 @@ public Task PersonalSign(string message) return Task.FromResult(signature); } - public Task SignTypedDataV4(string json) + public virtual Task SignTypedDataV4(string json) { if (string.IsNullOrEmpty(json)) { @@ -90,7 +84,7 @@ public Task SignTypedDataV4(string json) return Task.FromResult(signature); } - public Task SignTypedDataV4(T data, TypedData typedData) + public virtual Task SignTypedDataV4(T data, TypedData typedData) where TDomain : IDomain { if (data == null) @@ -103,7 +97,7 @@ public Task SignTypedDataV4(T data, TypedData typed return Task.FromResult(signature); } - public async Task SignTransaction(TransactionInput transaction, BigInteger chainId) + public virtual async Task SignTransaction(TransactionInput transaction, BigInteger chainId) { if (transaction == null) { @@ -163,12 +157,12 @@ public async Task SignTransaction(TransactionInput transaction, BigInteg return "0x" + signedTransaction; } - public Task IsConnected() + public virtual Task IsConnected() { return Task.FromResult(_ecKey != null); } - public Task Disconnect() + public virtual Task Disconnect() { _ecKey = null; return Task.CompletedTask; diff --git a/Thirdweb/Thirdweb.Wallets/SmartAccount/SmartAccount.cs b/Thirdweb/Thirdweb.Wallets/SmartAccount/SmartAccount.cs index 5ac0ec5..3b698b8 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartAccount/SmartAccount.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartAccount/SmartAccount.cs @@ -16,68 +16,81 @@ public class SmartAccount : IThirdwebAccount { public ThirdwebAccountType AccountType => ThirdwebAccountType.SmartAccount; - private ThirdwebClient _client; - private IThirdwebAccount _personalAccount; - private string _factoryAddress; - private bool _gasless; - private ThirdwebContract _factoryContract; - private ThirdwebContract _accountContract; - private ThirdwebContract _entryPointContract; - private BigInteger _chainId; - private string _bundlerUrl; - private string _paymasterUrl; - private string _entryPoint; - private string _accountAddressOverride; - - public SmartAccount( + protected ThirdwebClient _client; + protected IThirdwebAccount _personalAccount; + protected bool _gasless; + protected ThirdwebContract _factoryContract; + protected ThirdwebContract _accountContract; + protected ThirdwebContract _entryPointContract; + protected BigInteger _chainId; + protected string _bundlerUrl; + protected string _paymasterUrl; + + protected SmartAccount( ThirdwebClient client, IThirdwebAccount personalAccount, - string factoryAddress, bool gasless, BigInteger chainId, - string accountAddressOverride = null, - string entryPoint = null, - string bundlerUrl = null, - string paymasterUrl = null + string bundlerUrl, + string paymasterUrl, + ThirdwebContract entryPointContract, + ThirdwebContract factoryContract, + ThirdwebContract accountContract ) { _client = client; _personalAccount = personalAccount; - _factoryAddress = factoryAddress; _gasless = gasless; _chainId = chainId; - _accountAddressOverride = accountAddressOverride; - _entryPoint ??= Constants.DEFAULT_ENTRYPOINT_ADDRESS; - _bundlerUrl ??= $"https://{chainId}.bundler.thirdweb.com"; - _paymasterUrl ??= $"https://{chainId}.bundler.thirdweb.com"; + _bundlerUrl = bundlerUrl; + _paymasterUrl = paymasterUrl; + _entryPointContract = entryPointContract; + _factoryContract = factoryContract; + _accountContract = accountContract; } - public async Task Connect() + public static async Task Create( + ThirdwebClient client, + IThirdwebAccount personalAccount, + string factoryAddress, + bool gasless, + BigInteger chainId, + string accountAddressOverride = null, + string entryPoint = null, + string bundlerUrl = null, + string paymasterUrl = null + ) { - if (!await _personalAccount.IsConnected()) + if (!await personalAccount.IsConnected()) { throw new InvalidOperationException("SmartAccount.Connect: Personal account must be connected."); } - _entryPointContract = new ThirdwebContract( - _client, - _entryPoint, - _chainId, + bundlerUrl ??= $"https://{chainId}.bundler.thirdweb.com"; + paymasterUrl ??= $"https://{chainId}.bundler.thirdweb.com"; + entryPoint ??= Constants.DEFAULT_ENTRYPOINT_ADDRESS; + + var entryPointContract = await ThirdwebContract.Create( + client, + entryPoint, + chainId, "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bool\",\"name\":\"targetSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"targetResult\",\"type\":\"bytes\"}],\"name\":\"ExecutionResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"opIndex\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"FailedOp\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderAddressResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureValidationFailed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResult\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"struct IStakeManager.StakeInfo\",\"name\":\"stakeInfo\",\"type\":\"tuple\"}],\"internalType\":\"struct IEntryPoint.AggregatorStakeInfo\",\"name\":\"aggregatorInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResultWithAggregation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"}],\"name\":\"AccountDeployed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"BeforeExecution\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalDeposit\",\"type\":\"uint256\"}],\"name\":\"Deposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureAggregatorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalStaked\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"name\":\"StakeLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"withdrawTime\",\"type\":\"uint256\"}],\"name\":\"StakeUnlocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasUsed\",\"type\":\"uint256\"}],\"name\":\"UserOperationEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"revertReason\",\"type\":\"bytes\"}],\"name\":\"UserOperationRevertReason\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SIG_VALIDATION_FAILED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"}],\"name\":\"_validateSenderAndPaymaster\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"}],\"name\":\"addStake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"depositTo\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"deposits\",\"outputs\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getDepositInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"internalType\":\"struct IStakeManager.DepositInfo\",\"name\":\"info\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"key\",\"type\":\"uint192\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"name\":\"getSenderAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"getUserOpHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation[]\",\"name\":\"userOps\",\"type\":\"tuple[]\"},{\"internalType\":\"contract IAggregator\",\"name\":\"aggregator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct IEntryPoint.UserOpsPerAggregator[]\",\"name\":\"opsPerAggregator\",\"type\":\"tuple[]\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleAggregatedOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation[]\",\"name\":\"ops\",\"type\":\"tuple[]\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint192\",\"name\":\"key\",\"type\":\"uint192\"}],\"name\":\"incrementNonce\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"}],\"internalType\":\"struct EntryPoint.MemoryUserOp\",\"name\":\"mUserOp\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"contextOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"}],\"internalType\":\"struct EntryPoint.UserOpInfo\",\"name\":\"opInfo\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"context\",\"type\":\"bytes\"}],\"name\":\"innerHandleOp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"\",\"type\":\"uint192\"}],\"name\":\"nonceSequenceNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"op\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"targetCallData\",\"type\":\"bytes\"}],\"name\":\"simulateHandleOp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct UserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"simulateValidation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unlockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"withdrawAddress\",\"type\":\"address\"}],\"name\":\"withdrawStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"withdrawAmount\",\"type\":\"uint256\"}],\"name\":\"withdrawTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]" ); - _factoryContract = new ThirdwebContract( - _client, - _factoryAddress, - _chainId, + var factoryContract = await ThirdwebContract.Create( + client, + factoryAddress, + chainId, "[{\"type\": \"constructor\",\"name\": \"\",\"inputs\": [{\"type\": \"address\",\"name\": \"_defaultAdmin\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"_entrypoint\",\"internalType\": \"contract IEntryPoint\"},{\"type\": \"tuple[]\",\"name\": \"_defaultExtensions\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension[]\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"error\",\"name\": \"InvalidCodeAtRange\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_size\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_start\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_end\",\"internalType\": \"uint256\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"WriteError\",\"inputs\": [],\"outputs\": []},{\"type\": \"event\",\"name\": \"AccountCreated\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"accountAdmin\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ContractURIUpdated\",\"inputs\": [{\"type\": \"string\",\"name\": \"prevURI\",\"indexed\": false,\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"newURI\",\"indexed\": false,\"internalType\": \"string\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionAdded\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionRemoved\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"ExtensionReplaced\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"tuple\",\"name\": \"extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"indexed\": false,\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FunctionDisabled\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"indexed\": true,\"internalType\": \"bytes4\"},{\"type\": \"tuple\",\"name\": \"extMetadata\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"FunctionEnabled\",\"inputs\": [{\"type\": \"string\",\"name\": \"name\",\"indexed\": true,\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"indexed\": true,\"internalType\": \"bytes4\"},{\"type\": \"tuple\",\"name\": \"extFunction\",\"components\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"},{\"type\": \"string\",\"name\": \"functionSignature\",\"internalType\": \"string\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionFunction\"},{\"type\": \"tuple\",\"name\": \"extMetadata\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"indexed\": false,\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleAdminChanged\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"previousAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"bytes32\",\"name\": \"newAdminRole\",\"indexed\": true,\"internalType\": \"bytes32\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleGranted\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"RoleRevoked\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignerAdded\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"signer\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignerRemoved\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"signer\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"fallback\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"DEFAULT_ADMIN_ROLE\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"_disableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"accountImplementation\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"addExtension\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"contractURI\",\"inputs\": [],\"outputs\": [{\"type\": \"string\",\"name\": \"\",\"internalType\": \"string\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"createAccount\",\"inputs\": [{\"type\": \"address\",\"name\": \"_admin\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"_data\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"defaultExtensions\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"disableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"enableFunctionInExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"},{\"type\": \"tuple\",\"name\": \"_function\",\"components\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"},{\"type\": \"string\",\"name\": \"functionSignature\",\"internalType\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"entrypoint\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAccounts\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"_start\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"_end\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address[]\",\"name\": \"accounts\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAccountsOfSigner\",\"inputs\": [{\"type\": \"address\",\"name\": \"signer\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"address[]\",\"name\": \"accounts\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAddress\",\"inputs\": [{\"type\": \"address\",\"name\": \"_adminSigner\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"_data\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAllAccounts\",\"inputs\": [],\"outputs\": [{\"type\": \"address[]\",\"name\": \"\",\"internalType\": \"address[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getAllExtensions\",\"inputs\": [],\"outputs\": [{\"type\": \"tuple[]\",\"name\": \"allExtensions\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension[]\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"extensionName\",\"internalType\": \"string\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getImplementationForFunction\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"_functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getMetadataForFunction\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"functionSelector\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"\",\"components\": [{\"type\": \"string\",\"name\": \"name\",\"internalType\": \"string\"},{\"type\": \"string\",\"name\": \"metadataURI\",\"internalType\": \"string\"},{\"type\": \"address\",\"name\": \"implementation\",\"internalType\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleAdmin\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMember\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"index\",\"internalType\": \"uint256\"}],\"outputs\": [{\"type\": \"address\",\"name\": \"member\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getRoleMemberCount\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"count\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"grantRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"hasRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"hasRoleWithSwitch\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"isRegistered\",\"inputs\": [{\"type\": \"address\",\"name\": \"_account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"multicall\",\"inputs\": [{\"type\": \"bytes[]\",\"name\": \"data\",\"internalType\": \"bytes[]\"}],\"outputs\": [{\"type\": \"bytes[]\",\"name\": \"results\",\"internalType\": \"bytes[]\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onRegister\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onSignerAdded\",\"inputs\": [{\"type\": \"address\",\"name\": \"_signer\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"onSignerRemoved\",\"inputs\": [{\"type\": \"address\",\"name\": \"_signer\",\"internalType\": \"address\"},{\"type\": \"bytes32\",\"name\": \"_salt\",\"internalType\": \"bytes32\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"removeExtension\",\"inputs\": [{\"type\": \"string\",\"name\": \"_extensionName\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"renounceRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"replaceExtension\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"_extension\",\"components\": [{\"type\": \"tuple\",\"name\": \"metadata\",\"components\": [{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"metadataURI\",\"type\": \"string\"},{\"internalType\": \"address\",\"name\": \"implementation\",\"type\": \"address\"}],\"internalType\": \"struct IExtension.ExtensionMetadata\"},{\"type\": \"tuple[]\",\"name\": \"functions\",\"components\": [{\"internalType\": \"bytes4\",\"name\": \"functionSelector\",\"type\": \"bytes4\"},{\"internalType\": \"string\",\"name\": \"functionSignature\",\"type\": \"string\"}],\"internalType\": \"struct IExtension.ExtensionFunction[]\"}],\"internalType\": \"struct IExtension.Extension\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"revokeRole\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"role\",\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"setContractURI\",\"inputs\": [{\"type\": \"string\",\"name\": \"_uri\",\"internalType\": \"string\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"totalAccounts\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"}]" ); - var accountAddress = _accountAddressOverride ?? await ThirdwebContract.ReadContract(_factoryContract, "getAddress", await _personalAccount.GetAddress(), new byte[0]); - _accountContract = new ThirdwebContract( - _client, + var accountAddress = accountAddressOverride ?? await ThirdwebContract.Read(factoryContract, "getAddress", await personalAccount.GetAddress(), new byte[0]); + var accountContract = await ThirdwebContract.Create( + client, accountAddress, - _chainId, + chainId, "[{type: \"constructor\",inputs: [{name: \"_entrypoint\",type: \"address\",internalType: \"contract IEntryPoint\",},{ name: \"_factory\", type: \"address\", internalType: \"address\" },],stateMutability: \"nonpayable\",},{ type: \"receive\", stateMutability: \"payable\" },{type: \"function\",name: \"addDeposit\",inputs: [],outputs: [],stateMutability: \"payable\",},{type: \"function\",name: \"contractURI\",inputs: [],outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],stateMutability: \"view\",},{type: \"function\",name: \"entryPoint\",inputs: [],outputs: [{ name: \"\", type: \"address\", internalType: \"contract IEntryPoint\" },],stateMutability: \"view\",},{type: \"function\",name: \"execute\",inputs: [{ name: \"_target\", type: \"address\", internalType: \"address\" },{ name: \"_value\", type: \"uint256\", internalType: \"uint256\" },{ name: \"_calldata\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"executeBatch\",inputs: [{ name: \"_target\", type: \"address[]\", internalType: \"address[]\" },{ name: \"_value\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"_calldata\", type: \"bytes[]\", internalType: \"bytes[]\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"factory\",inputs: [],outputs: [{ name: \"\", type: \"address\", internalType: \"address\" }],stateMutability: \"view\",},{type: \"function\",name: \"getAllActiveSigners\",inputs: [],outputs: [{name: \"signers\",type: \"tuple[]\",internalType: \"struct IAccountPermissions.SignerPermissions[]\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"getAllAdmins\",inputs: [],outputs: [{ name: \"\", type: \"address[]\", internalType: \"address[]\" }],stateMutability: \"view\",},{type: \"function\",name: \"getAllSigners\",inputs: [],outputs: [{name: \"signers\",type: \"tuple[]\",internalType: \"struct IAccountPermissions.SignerPermissions[]\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"getMessageHash\",inputs: [{ name: \"_hash\", type: \"bytes32\", internalType: \"bytes32\" }],outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],stateMutability: \"view\",},{type: \"function\",name: \"getNonce\",inputs: [],outputs: [{ name: \"\", type: \"uint256\", internalType: \"uint256\" }],stateMutability: \"view\",},{type: \"function\",name: \"getPermissionsForSigner\",inputs: [{ name: \"signer\", type: \"address\", internalType: \"address\" }],outputs: [{name: \"\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissions\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{ name: \"startTimestamp\", type: \"uint128\", internalType: \"uint128\" },{ name: \"endTimestamp\", type: \"uint128\", internalType: \"uint128\" },],},],stateMutability: \"view\",},{type: \"function\",name: \"initialize\",inputs: [{ name: \"_defaultAdmin\", type: \"address\", internalType: \"address\" },{ name: \"_data\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"isActiveSigner\",inputs: [{ name: \"signer\", type: \"address\", internalType: \"address\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"isAdmin\",inputs: [{ name: \"_account\", type: \"address\", internalType: \"address\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"isValidSignature\",inputs: [{ name: \"_hash\", type: \"bytes32\", internalType: \"bytes32\" },{ name: \"_signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"magicValue\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"view\",},{type: \"function\",name: \"isValidSigner\",inputs: [{ name: \"_signer\", type: \"address\", internalType: \"address\" },{name: \"_userOp\",type: \"tuple\",internalType: \"struct UserOperation\",components: [{ name: \"sender\", type: \"address\", internalType: \"address\" },{ name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },{ name: \"initCode\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callGasLimit\", type: \"uint256\", internalType: \"uint256\" },{name: \"verificationGasLimit\",type: \"uint256\",internalType: \"uint256\",},{name: \"preVerificationGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"maxFeePerGas\", type: \"uint256\", internalType: \"uint256\" },{name: \"maxPriorityFeePerGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"paymasterAndData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],},],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"multicall\",inputs: [{ name: \"data\", type: \"bytes[]\", internalType: \"bytes[]\" }],outputs: [{ name: \"results\", type: \"bytes[]\", internalType: \"bytes[]\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC1155BatchReceived\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"\", type: \"uint256[]\", internalType: \"uint256[]\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC1155Received\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"onERC721Received\",inputs: [{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"address\", internalType: \"address\" },{ name: \"\", type: \"uint256\", internalType: \"uint256\" },{ name: \"\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"\", type: \"bytes4\", internalType: \"bytes4\" }],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setContractURI\",inputs: [{ name: \"_uri\", type: \"string\", internalType: \"string\" }],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setEntrypointOverride\",inputs: [{name: \"_entrypointOverride\",type: \"address\",internalType: \"contract IEntryPoint\",},],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"setPermissionsForSigner\",inputs: [{name: \"_req\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},{ name: \"_signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"function\",name: \"supportsInterface\",inputs: [{ name: \"interfaceId\", type: \"bytes4\", internalType: \"bytes4\" }],outputs: [{ name: \"\", type: \"bool\", internalType: \"bool\" }],stateMutability: \"view\",},{type: \"function\",name: \"validateUserOp\",inputs: [{name: \"userOp\",type: \"tuple\",internalType: \"struct UserOperation\",components: [{ name: \"sender\", type: \"address\", internalType: \"address\" },{ name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },{ name: \"initCode\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"callGasLimit\", type: \"uint256\", internalType: \"uint256\" },{name: \"verificationGasLimit\",type: \"uint256\",internalType: \"uint256\",},{name: \"preVerificationGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"maxFeePerGas\", type: \"uint256\", internalType: \"uint256\" },{name: \"maxPriorityFeePerGas\",type: \"uint256\",internalType: \"uint256\",},{ name: \"paymasterAndData\", type: \"bytes\", internalType: \"bytes\" },{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],},{ name: \"userOpHash\", type: \"bytes32\", internalType: \"bytes32\" },{ name: \"missingAccountFunds\", type: \"uint256\", internalType: \"uint256\" },],outputs: [{ name: \"validationData\", type: \"uint256\", internalType: \"uint256\" },],stateMutability: \"nonpayable\",},{type: \"function\",name: \"verifySignerPermissionRequest\",inputs: [{name: \"req\",type: \"tuple\",internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},{ name: \"signature\", type: \"bytes\", internalType: \"bytes\" },],outputs: [{ name: \"success\", type: \"bool\", internalType: \"bool\" },{ name: \"signer\", type: \"address\", internalType: \"address\" },],stateMutability: \"view\",},{type: \"function\",name: \"withdrawDepositTo\",inputs: [{name: \"withdrawAddress\",type: \"address\",internalType: \"address payable\",},{ name: \"amount\", type: \"uint256\", internalType: \"uint256\" },],outputs: [],stateMutability: \"nonpayable\",},{type: \"event\",name: \"AdminUpdated\",inputs: [{name: \"signer\",type: \"address\",indexed: true,internalType: \"address\",},{ name: \"isAdmin\", type: \"bool\", indexed: false, internalType: \"bool\" },],anonymous: false,},{type: \"event\",name: \"ContractURIUpdated\",inputs: [{name: \"prevURI\",type: \"string\",indexed: false,internalType: \"string\",},{name: \"newURI\",type: \"string\",indexed: false,internalType: \"string\",},],anonymous: false,},{type: \"event\",name: \"Initialized\",inputs: [{ name: \"version\", type: \"uint8\", indexed: false, internalType: \"uint8\" },],anonymous: false,},{type: \"event\",name: \"SignerPermissionsUpdated\",inputs: [{name: \"authorizingSigner\",type: \"address\",indexed: true,internalType: \"address\",},{name: \"targetSigner\",type: \"address\",indexed: true,internalType: \"address\",},{name: \"permissions\",type: \"tuple\",indexed: false,internalType: \"struct IAccountPermissions.SignerPermissionRequest\",components: [{ name: \"signer\", type: \"address\", internalType: \"address\" },{ name: \"isAdmin\", type: \"uint8\", internalType: \"uint8\" },{name: \"approvedTargets\",type: \"address[]\",internalType: \"address[]\",},{name: \"nativeTokenLimitPerTransaction\",type: \"uint256\",internalType: \"uint256\",},{name: \"permissionStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"permissionEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityStartTimestamp\",type: \"uint128\",internalType: \"uint128\",},{name: \"reqValidityEndTimestamp\",type: \"uint128\",internalType: \"uint128\",},{ name: \"uid\", type: \"bytes32\", internalType: \"bytes32\" },],},],anonymous: false,},]" ); + + return new SmartAccount(client, personalAccount, gasless, chainId, bundlerUrl, paymasterUrl, entryPointContract, factoryContract, accountContract); } public async Task IsDeployed() @@ -104,7 +117,7 @@ private async Task GetInitCode() } var data = new Contract(null, _factoryContract.Abi, _factoryContract.Address).GetFunction("createAccount").GetData(await _personalAccount.GetAddress(), new byte[0]); - data = Utils.HexConcat(_factoryAddress, data); + data = Utils.HexConcat(_factoryContract.Address, data); return data.HexToByteArray(); } @@ -148,7 +161,7 @@ private async Task SignUserOp(TransactionInput transactionInput, // Estimate gas - var gasEstimates = await BundlerClient.EthEstimateUserOperationGas(_client, _bundlerUrl, requestId, EncodeUserOperation(partialUserOp), _entryPoint); + var gasEstimates = await BundlerClient.EthEstimateUserOperationGas(_client, _bundlerUrl, requestId, EncodeUserOperation(partialUserOp), _entryPointContract.Address); partialUserOp.CallGasLimit = 50000 + new HexBigInteger(gasEstimates.CallGasLimit).Value; partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGas).Value; partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; @@ -170,7 +183,7 @@ private async Task SendUserOp(UserOperation userOperation, int? requestI // Send the user operation - var userOpHash = await BundlerClient.EthSendUserOperation(_client, _bundlerUrl, requestId, EncodeUserOperation(userOperation), _entryPoint); + var userOpHash = await BundlerClient.EthSendUserOperation(_client, _bundlerUrl, requestId, EncodeUserOperation(userOperation), _entryPointContract.Address); // Wait for the transaction to be mined @@ -191,14 +204,14 @@ private async Task GetNonce() RandomNumberGenerator.Fill(randomBytes); BigInteger randomInt192 = new(randomBytes); randomInt192 = BigInteger.Abs(randomInt192) % (BigInteger.One << 192); - return await ThirdwebContract.ReadContract(_entryPointContract, "getNonce", await GetAddress(), randomInt192); + return await ThirdwebContract.Read(_entryPointContract, "getNonce", await GetAddress(), randomInt192); } private async Task GetPaymasterAndData(object requestId, UserOperationHexified userOp) { if (_gasless) { - var paymasterAndData = await BundlerClient.PMSponsorUserOperation(_client, _paymasterUrl, requestId, userOp, _entryPoint); + var paymasterAndData = await BundlerClient.PMSponsorUserOperation(_client, _paymasterUrl, requestId, userOp, _entryPointContract.Address); return paymasterAndData.paymasterAndData.HexToByteArray(); } else @@ -209,7 +222,7 @@ private async Task GetPaymasterAndData(object requestId, UserOperationHe private async Task HashAndSignUserOp(UserOperation userOp, ThirdwebContract entryPointContract) { - var userOpHash = await ThirdwebContract.ReadContract(entryPointContract, "getUserOpHash", userOp); + var userOpHash = await ThirdwebContract.Read(entryPointContract, "getUserOpHash", userOp); var sig = await _personalAccount.PersonalSign(userOpHash); return sig.HexToByteArray(); } @@ -232,7 +245,7 @@ private UserOperationHexified EncodeUserOperation(UserOperation userOperation) }; } - internal async Task ForceDeploy() + public async Task ForceDeploy() { var input = new TransactionInput("0x", _accountContract.Address, new HexBigInteger(0)); var txHash = await SendTransaction(input); @@ -272,7 +285,7 @@ public async Task PersonalSign(string message) bool factorySupports712; try { - _ = await ThirdwebContract.ReadContract(_accountContract, "getMessageHash", originalMsgHash); + _ = await ThirdwebContract.Read(_accountContract, "getMessageHash", originalMsgHash); factorySupports712 = true; } catch @@ -297,7 +310,7 @@ public async Task IsValidSignature(string message, string signature) { try { - var magicValue = await ThirdwebContract.ReadContract(_accountContract, "isValidSignature", message.HashPrefixedMessage().HexToByteArray(), signature.HexToByteArray()); + var magicValue = await ThirdwebContract.Read(_accountContract, "isValidSignature", message.HashPrefixedMessage().HexToByteArray(), signature.HexToByteArray()); return magicValue.ToHex(true) == new byte[] { 0x16, 0x26, 0xba, 0x7e }.ToHex(true); } catch (Exception e) diff --git a/Thirdweb/Thirdweb.Wallets/ThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/ThirdwebWallet.cs deleted file mode 100644 index 49e3c8e..0000000 --- a/Thirdweb/Thirdweb.Wallets/ThirdwebWallet.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Numerics; -using Nethereum.ABI.EIP712; -using Nethereum.RPC.Eth.DTOs; - -namespace Thirdweb -{ - public class ThirdwebWallet - { - public Dictionary Accounts { get; } - public IThirdwebAccount ActiveAccount { get; private set; } - - public ThirdwebWallet() - { - Accounts = new Dictionary(); - ActiveAccount = null; - } - - public async Task Initialize(List accounts) - { - if (accounts.Count == 0) - { - throw new ArgumentException("At least one account must be provided."); - } - - for (var i = 0; i < accounts.Count; i++) - { - if (!await accounts[i].IsConnected()) - { - throw new InvalidOperationException($"Account at index {i} is not connected."); - } - } - - foreach (var account in accounts) - { - Accounts.Add(await account.GetAddress(), account); - } - - SetActive(Accounts.Keys.First()); - } - - public void SetActive(string address) - { - if (!Accounts.ContainsKey(address)) - { - throw new ArgumentException($"Account with address {address} not found."); - } - - ActiveAccount = Accounts[address]; - } - - public async Task GetAddress() - { - return await ActiveAccount.GetAddress(); - } - - public async Task EthSign(string message) - { - return await ActiveAccount.EthSign(message); - } - - public async Task PersonalSign(string message) - { - return await ActiveAccount.PersonalSign(message); - } - - public async Task SignTypedDataV4(string json) - { - return await ActiveAccount.SignTypedDataV4(json); - } - - public async Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain - { - return await ActiveAccount.SignTypedDataV4(data, typedData); - } - - public async Task SignTransaction(TransactionInput transaction, BigInteger chainId) - { - return await ActiveAccount.SignTransaction(transaction, chainId); - } - - public async Task IsConnected() - { - return await ActiveAccount.IsConnected(); - } - - public async Task DisconnectAll() - { - foreach (var account in Accounts.Values) - { - await account.Disconnect(); - } - } - } -}