-
Notifications
You must be signed in to change notification settings - Fork 6
v3 #157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
v3 #157
Conversation
Introduces a new /auth/social endpoint for OAuth flows, deprecates the old OAuth method, and updates documentation accordingly. Refactors payments API: renames and restructures payment creation, completion, and history endpoints, and moves token swap functionality to a new bridge/swap endpoint. Expands wallet token retrieval with new filtering and sorting options.
Deleted the User class and the VerifyResult class that referenced it from EmbeddedWallet.Misc.cs. Also removed the Nethereum.HdWallet package reference from the project file, likely as part of cleaning up unused code and dependencies.
Moved and consolidated RPC-related types into Thirdweb.RPC namespace, replacing previous implementations. Updated all references and usages to the new types and namespace throughout the codebase. Renamed BundlerClient to ThirdwebBundler and updated all relevant calls. This improves code organization and clarity for RPC handling.
Eliminated the unnecessary Nethereum.JsonRpc.Client.RpcMessages import and added Thirdweb.RPC import to clean up dependencies in ThirdwebBundler.cs.
Replaced usage of Nethereum.RLP with a custom RLP implementation in Thirdweb.Wallets. Removed PrivateKeyWallet and related RLP-based transaction decoding from Utils. Updated ThirdwebRPC to use JTokenType for error handling. This refactor reduces external dependencies and centralizes RLP logic.
Replaced usage of PrivateKeyWallet with InAppWallet using AuthProvider.Guest across all tests and sample code. Removed PrivateKeyWallet-specific tests and helper methods, consolidating wallet creation to use guest accounts for consistency and future compatibility.
Deleted EngineWallet.cs as the EngineWallet class is obsolete and scheduled for removal. Developers should use ServerWallet instead.
Deleted all ThirdwebPay payment-related files, including crypto and fiat payment processing, quote/status retrieval, and associated types. This module was marked as deprecated in favor of ThirdwebBridge.
Deleted all files related to Thirdweb.AI and Thirdweb.Indexer, including clients, types, and extension methods. This removes Nebula chat, execution, session management, and insight functionality from the codebase.
Deleted large blocks of commented-out code related to Indexer and AI features in Program.cs to clean up the file and improve readability.
Deleted Thirdweb.AI.Tests.cs to remove Nebula-related tests. Renamed GeneratedClient.cs to ThirdwebApi.cs and updated nswag.json output path to reflect the new filename for consistency.
Deleted VerificationException and UserStatus as they are no longer used. Refactored DataStorage to use auto-properties with DataMember attributes instead of backing fields, simplifying the class structure.
Renamed EIP712.cs, EIP712Encoder.cs, and RLP.cs from the Wallets folder to the Utils folder to better reflect their utility nature and improve project organization.
Moved several classes from Thirdweb.RPC and Thirdweb.Bridge namespaces to Thirdweb, and removed unused Thirdweb.RPC references across the codebase. Consolidated TimeoutOptions and TimeoutType into ThirdwebClient.Types.cs, and moved ThirdwebTransactionReceipt into ThirdwebTransaction.Types.cs. Performed file renames for consistency and reorganized EmbeddedWallet files under Thirdweb.EWS. Cleaned up obsolete interface and type files.
WalkthroughThe PR removes Nebula AI, Insight Indexer, and Pay modules; deletes PrivateKeyWallet and ETH-sign/recovery APIs; refactors SmartWallet to use ThirdwebBundler and CreateCallData; consolidates RPC types; simplifies transaction revert handling; adds an RLP encoder; updates Embedded/In-App wallet EWS storage and OAuth flows; adjusts Bridge namespaces; changes client timeout types; updates samples/tests to use guest InAppWallet. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant App
participant SmartWallet
participant ThirdwebBundler
participant EntryPoint
App->>SmartWallet: create/prepare userOp (createCallData)
SmartWallet->>ThirdwebBundler: ThirdwebGetUserOperationGasPrice
ThirdwebBundler-->>SmartWallet: gas price data
SmartWallet->>ThirdwebBundler: PMSponsorUserOperation / ZkPaymasterData (if gasless/erc20)
ThirdwebBundler-->>SmartWallet: sponsor data
SmartWallet->>ThirdwebBundler: EthSendUserOperation(userOp)
ThirdwebBundler-->>SmartWallet: userOpHash
SmartWallet->>ThirdwebBundler: EthGetUserOperationReceipt(userOpHash)
ThirdwebBundler-->>SmartWallet: receipt (success/fail)
SmartWallet-->>App: tx hash / throw "execution reverted" on Status==0
Note over SmartWallet: Revert reason decoding removed
sequenceDiagram
autonumber
participant App
participant EmbeddedWallet
participant EWS_Server
App->>EmbeddedWallet: SignInWithOauthAsync(authResult)
activate EmbeddedWallet
EmbeddedWallet->>EWS_Server: VerifyOAuth(authResult)
EWS_Server-->>EmbeddedWallet: VerifyResult(token, user ids, ...)
EmbeddedWallet-->>App: VerifyResult (sync return)
deactivate EmbeddedWallet
Note over EmbeddedWallet: Removed async token exchange / lambda path
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Pre-merge checks (2 warnings, 1 inconclusive)❌ Failed Checks (2 warnings, 1 inconclusive)
✨ Finishing Touches
🧪 Generate unit tests
Comment |
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (11)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs (1)
9-26
: RenameAuthToken
toCookieString
inVerifyResult
and update all.AuthToken
usages
- Apply the diff below in
Server.Types.cs
to make intent explicit and add an obsolete shim.- Update every call site that reads
VerifyResult.AuthToken
or passes anauthToken
—including inServer.cs
,EcosystemWallet.cs
(headers, session data, link/unlink calls) andLocalStorage.Types.cs
—to useCookieString
(or fall back toAuthToken
via the shim).- internal VerifyResult(string authProvider, bool isNewUser, string authToken, string walletUserId, string email, string phoneNumber, string authIdentifier) + internal VerifyResult(string authProvider, bool isNewUser, string cookieString, string walletUserId, string email, string phoneNumber, string authIdentifier) { this.AuthProvider = authProvider; this.IsNewUser = isNewUser; - this.AuthToken = authToken; + this.CookieString = cookieString; this.WalletUserId = walletUserId; this.Email = email; this.PhoneNumber = phoneNumber; this.AuthIdentifier = authIdentifier; } internal string AuthProvider { get; } internal bool IsNewUser { get; } - internal string AuthToken { get; } + internal string CookieString { get; } + + [System.Obsolete("Use CookieString; this was previously misnamed.")] + internal string AuthToken => CookieString; internal string WalletUserId { get; } internal string Email { get; } internal string PhoneNumber { get; } internal string AuthIdentifier { get; }Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs (1)
376-386
: Bug: Status mapping ignores PROCESSING and CREATEDStatusData.StatusType maps only FAILED/PENDING/COMPLETED/NOT_FOUND, causing PROCESSING/CREATED to resolve to UNKNOWN (while OnrampStatusData handles them). This leads to inconsistent behavior and premature loop exits downstream.
Apply:
- public StatusType StatusType => - this.Status switch - { - "FAILED" => StatusType.FAILED, - "PENDING" => StatusType.PENDING, - "COMPLETED" => StatusType.COMPLETED, - "NOT_FOUND" => StatusType.NOT_FOUND, - _ => StatusType.UNKNOWN, - }; + public StatusType StatusType => + this.Status switch + { + "FAILED" => StatusType.FAILED, + "PENDING" => StatusType.PENDING, + "COMPLETED" => StatusType.COMPLETED, + "NOT_FOUND" => StatusType.NOT_FOUND, + "PROCESSING" => StatusType.PROCESSING, + "CREATED" => StatusType.CREATED, + _ => StatusType.UNKNOWN, + };Also applies to: 395-405
Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs (1)
85-99
: Guard against null/empty steps and transactions to avoid NREspreparedTransfer.Transactions can be null; enumerating step.Transactions will throw.
- private static async Task<List<ThirdwebTransactionReceipt>> ExecuteInternal(this ThirdwebBridge bridge, IThirdwebWallet executor, List<Step> steps, CancellationToken cancellationToken = default) + private static async Task<List<ThirdwebTransactionReceipt>> ExecuteInternal(this ThirdwebBridge bridge, IThirdwebWallet executor, List<Step> steps, CancellationToken cancellationToken = default) { var receipts = new List<ThirdwebTransactionReceipt>(); - foreach (var step in steps) + if (steps == null || steps.Count == 0) + { + return receipts; + } + foreach (var step in steps) { - foreach (var tx in step.Transactions) + var txs = step?.Transactions; + if (txs == null || txs.Count == 0) continue; + foreach (var tx in txs) { 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); + await bridge.WaitForStatusCompletion(hash, tx.ChainId, cancellationToken); } } return receipts; }Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs (4)
58-66
: Validate destinationTokenAddress in Buy_QuoteOrigin is validated; destination isn’t. Add symmetric validation to fail fast on bad input.
if (!Utils.IsValidAddress(originTokenAddress)) { throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); } + if (!Utils.IsValidAddress(destinationTokenAddress)) + { + throw new ArgumentException("destinationTokenAddress is not a valid address", nameof(destinationTokenAddress)); + } + if (buyAmountWei <= 0) { throw new ArgumentException("buyAmountWei cannot be less than or equal to 0", nameof(buyAmountWei)); }
123-141
: Validate destinationTokenAddress in Buy_PrepareMirror origin validation for destination to avoid server-side 4xx.
if (!Utils.IsValidAddress(originTokenAddress)) { throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); } + if (!Utils.IsValidAddress(destinationTokenAddress)) + { + throw new ArgumentException("destinationTokenAddress is not a valid address", nameof(destinationTokenAddress)); + } + if (buyAmountWei <= 0) { throw new ArgumentException("buyAmountWei cannot be less than or equal to 0", nameof(buyAmountWei)); }
204-212
: Validate destinationTokenAddress in Sell_QuoteSame issue as Buy_Quote.
if (!Utils.IsValidAddress(originTokenAddress)) { throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); } + if (!Utils.IsValidAddress(destinationTokenAddress)) + { + throw new ArgumentException("destinationTokenAddress is not a valid address", nameof(destinationTokenAddress)); + } + if (sellAmountWei <= 0) { throw new ArgumentException("sellAmountWei cannot be less than or equal to 0", nameof(sellAmountWei)); }
269-287
: Validate destinationTokenAddress in Sell_PrepareMirror origin validation for destination.
if (!Utils.IsValidAddress(originTokenAddress)) { throw new ArgumentException("originTokenAddress is not a valid address", nameof(originTokenAddress)); } + if (!Utils.IsValidAddress(destinationTokenAddress)) + { + throw new ArgumentException("destinationTokenAddress is not a valid address", nameof(destinationTokenAddress)); + } + if (sellAmountWei <= 0) { throw new ArgumentException("sellAmountWei cannot be less than or equal to 0", nameof(sellAmountWei)); }Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs (1)
503-514
: Avoid async void in xUnit tests; use Task. Also rename misleading variable.Async void hides test failures. Use Task and rename pkWallet to guestWallet to match GetGuestAccount().
-[Fact(Timeout = 120000)] -public async void ToJsonExternalWalletFriendly_ReturnsCorrectValue4() +[Fact(Timeout = 120000)] +public async Task ToJsonExternalWalletFriendly_ReturnsCorrectValue4() { - var pkWallet = await this.GetGuestAccount(); // Assume external wallet + var guestWallet = await this.GetGuestAccount(); // Guest InApp wallet var msg = new AccountAbstraction.AccountMessage { Message = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; - var verifyingContract = await pkWallet.GetAddress(); // doesn't matter here + var verifyingContract = await guestWallet.GetAddress(); // doesn't matter hereThirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs (2)
301-351
: ERC-6492 decoding slices by character count, not bytes (broken for hex strings).You subtract 32 from the string length when trimming the magic suffix, but Take() is applied to the byte array. This corrupts the payload for nontrivial signatures.
- var erc6492Sig = new ABIEncode().DecodeEncodedComplexType<Erc6492Signature>(signature.HexToBytes().Take(signature.Length - 32).ToArray()); + var sigBytes = signature.HexToBytes(); + var erc6492Sig = new ABIEncode().DecodeEncodedComplexType<Erc6492Signature>(sigBytes.Take(sigBytes.Length - 32).ToArray());
1217-1225
: Account ABI hardcoded to V06 after network switch (breaks V07 accounts).Use the entry point version to select the correct account ABI, mirroring Create().
- 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._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<string>(this._factoryContract, "getAddress", personalAddress, Array.Empty<byte>()).ConfigureAwait(false); - this._accountContract = await ThirdwebContract.Create(this._personalAccount.Client, accountAddress, chainId, Constants.ACCOUNT_V06_ABI).ConfigureAwait(false); + var entryPointVersion = Utils.GetEntryPointVersion(this._entryPointContract.Address); + var accountAbi = entryPointVersion == 6 ? Constants.ACCOUNT_V06_ABI : Constants.ACCOUNT_V07_ABI; + this._accountContract = await ThirdwebContract.Create(this._personalAccount.Client, accountAddress, chainId, accountAbi).ConfigureAwait(false);Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs (1)
315-319
: Persisting session with async void is unsafe; await persistence to avoid race conditions.CreateEnclaveSession ultimately calls EmbeddedWallet.UpdateSessionData (async void). Exceptions are unobserved and writes can race subsequent reads.
Apply (in this file) to await persistence:
- CreateEnclaveSession(this.EmbeddedWallet, result.AuthToken, this.Email, this.PhoneNumber, this.AuthProvider, result.AuthIdentifier); + await CreateEnclaveSessionAsync(this.EmbeddedWallet, result.AuthToken, this.Email, this.PhoneNumber, this.AuthProvider, result.AuthIdentifier);And add an async counterpart:
private static async Task CreateEnclaveSessionAsync(EmbeddedWallet embeddedWallet, string authToken, string email, string phone, string authProvider, string authIdentifier) { var data = new LocalStorage.DataStorage(authToken, null, email, phone, null, authProvider, authIdentifier); await embeddedWallet.UpdateSessionDataAsync(data).ConfigureAwait(false); }Outside this file (supporting change in EmbeddedWallet):
// EmbeddedWallet.Misc.cs internal async Task UpdateSessionDataAsync(LocalStorage.DataStorage data) { await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); } // (Optionally keep old UpdateSessionData as a thin wrapper marked [Obsolete] calling the async version and .GetAwaiter().GetResult() for compatibility.)
🧹 Nitpick comments (33)
nswag.json (1)
67-67
: Optional: align filename with class nameThe generated class is ThirdwebApiClient; consider outputting ThirdwebApiClient.cs for conventional class-to-file alignment.
- "output": "Thirdweb/Thirdweb.Api/ThirdwebApi.cs" + "output": "Thirdweb/Thirdweb.Api/ThirdwebApiClient.cs"Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs (2)
36-47
: Tighten visibility of LinkedAccount types (nested under an internal container)These are declared public but are nested inside an internal type, which can be misleading. Prefer internal (and consider sealed) for clarity.
- public class LinkedAccount + internal sealed class LinkedAccount @@ - public class LinkedAccountDetails + internal sealed class LinkedAccountDetailsAlso applies to: 45-59
204-223
: Nullable auth details to reflect optional presence across providersEmail/Phone/AuthIdentifier are optional depending on provider, but typed as non-nullable strings. Mark as nullable to avoid incorrect assumptions and future NREs.
- internal string PhoneNumber { get; set; } + internal string? PhoneNumber { get; set; } @@ - internal string Email { get; set; } + internal string? Email { get; set; } @@ - internal string UserWalletId { get; set; } + internal string UserWalletId { get; set; } // required @@ - internal string AuthIdentifier { get; set; } + internal string? AuthIdentifier { get; set; } @@ - internal string RecoveryCode { get; set; } + internal string? RecoveryCode { get; set; } @@ - internal string RecoveryShareManagement { get; set; } + internal string? RecoveryShareManagement { get; set; }Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs (1)
76-76
: Doc comment nit: stray triple-slashThere’s an extra “///” prefix.
- /// /// <param name="bridge">The Thirdweb bridge.</param> + /// <param name="bridge">The Thirdweb bridge.</param>Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs (3)
432-432
: Locale-safe provider serializationUse ToLowerInvariant() to avoid culture-specific casing issues.
- onramp = onramp.ToString().ToLower(), + onramp = onramp.ToString().ToLowerInvariant(),
488-509
: Add cancellable Status overloadEnable end-to-end cancellation in polling paths.
public async Task<StatusData> Status(string transactionHash, BigInteger chainId) { if (string.IsNullOrWhiteSpace(transactionHash)) { throw new ArgumentException("transactionHash cannot be null or empty", nameof(transactionHash)); } @@ var result = JsonConvert.DeserializeObject<ResponseModel<StatusData>>(responseContent); return result.Data; } + + public async Task<StatusData> Status(string transactionHash, BigInteger chainId, CancellationToken cancellationToken) + { + 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<string, string> { { "transactionHash", transactionHash }, { "chainId", chainId.ToString() } }; + url = AppendQueryParams(url, queryParams); + var response = await this._httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false); + _ = response.EnsureSuccessStatusCode(); + var responseContent = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); + var result = JsonConvert.DeserializeObject<ResponseModel<StatusData>>(responseContent); + return result.Data; + }Then switch WaitForStatusCompletion to call this overload.
513-526
: URL-encode query parameters and avoid dangling '?'Current code doesn’t escape values and appends “?” even if no params survive filtering.
- private static string AppendQueryParams(string url, Dictionary<string, string> queryParams) + private static string AppendQueryParams(string url, Dictionary<string, string> queryParams) { - var query = new List<string>(); - foreach (var param in queryParams) - { - if (string.IsNullOrEmpty(param.Value)) - { - continue; - } - query.Add($"{param.Key}={param.Value}"); - } - - return url + "?" + string.Join("&", query); + var query = new List<string>(); + foreach (var param in queryParams) + { + if (string.IsNullOrEmpty(param.Value)) continue; + var k = Uri.EscapeDataString(param.Key); + var v = Uri.EscapeDataString(param.Value); + query.Add($"{k}={v}"); + } + if (query.Count == 0) return url; + return $"{url}?{string.Join("&", query)}"; }Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs (2)
5-8
: Drop redundant null-coalescing and expose nullable return type
_localStorage.Data
may be null; the?? null
is redundant. If nullable refs are enabled, returnDataStorage?
.- internal LocalStorage.DataStorage GetSessionData() + internal LocalStorage.DataStorage? GetSessionData() { - return this._localStorage.Data ?? null; + return this._localStorage.Data; }
15-18
: Clear session by saving null rather than an object of nullsThis more explicitly clears state and avoids persisting a payload full of null fields.
- public async Task SignOutAsync() - { - await this._localStorage.SaveDataAsync(new LocalStorage.DataStorage(null, null, null, null, null, null, null)).ConfigureAwait(false); - } + public Task SignOutAsync() + { + return this._localStorage.SaveDataAsync(null); + }Note: if nullable refs are enabled, also update
SaveDataAsync
signatures to acceptDataStorage?
(see comment in LocalStorage.Types.cs).Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs (2)
10-29
: Reduce file bloat by not emitting default valuesSkip serializing nulls to shrink file size and avoid persisting meaningless fields.
- [field: DataMember(Name = "authToken")] + [field: DataMember(Name = "authToken", EmitDefaultValue = false)] internal string AuthToken { get; } - [field: DataMember(Name = "deviceShare")] + [field: DataMember(Name = "deviceShare", EmitDefaultValue = false)] internal string DeviceShare { get; } - [field: DataMember(Name = "emailAddress")] + [field: DataMember(Name = "emailAddress", EmitDefaultValue = false)] internal string EmailAddress { get; } - [field: DataMember(Name = "phoneNumber")] + [field: DataMember(Name = "phoneNumber", EmitDefaultValue = false)] internal string PhoneNumber { get; } - [field: DataMember(Name = "walletUserId")] + [field: DataMember(Name = "walletUserId", EmitDefaultValue = false)] internal string WalletUserId { get; } - [field: DataMember(Name = "authProvider")] + [field: DataMember(Name = "authProvider", EmitDefaultValue = false)] internal string AuthProvider { get; } - [field: DataMember(Name = "authIdentifier")] + [field: DataMember(Name = "authIdentifier", EmitDefaultValue = false)] internal string AuthIdentifier { get; }
5-41
: Consider encrypting at rest or using OS-protected storageAuth token, device share, and identifiers are sensitive. Prefer DPAPI/Keychain/KeyStore or file-level encryption + ACLs.
If you want, I can sketch a thin abstraction that encrypts
Storage
blobs before writing and rotates keys.Thirdweb/Thirdweb.Utils/RLP.cs (6)
168-176
: Null handling for lists is surprising; prefer explicit behavior.Treating
(items.Length == 1 && items[0] == null)
as an empty list is non-obvious. Either throw or explicitly encode a null element (0x80) viaEncodeElement
.Apply:
- if (items == null || (items.Length == 1 && items[0] == null)) - { - return new[] { OFFSET_SHORT_LIST }; - } + if (items == null) + { + return new[] { OFFSET_SHORT_LIST }; + } + if (items.Any(i => i == null)) + { + throw new ArgumentNullException(nameof(items), "Null entries inside a list are not allowed; encode as empty element (0x80) explicitly."); + }
27-39
: Visibility consistency for RLP offset constants.
OFFSET_SHORT_LIST
is public while other offsets are private. Expose all or keep all private for consistency.Example options:
- Make all four offsets public.
- Or keep all private and expose a small API surface.
Also applies to: 48-58
12-13
: Nit: fix typo in comment.“cutof” → “cutoff”.
- /// - also, that's where Bitcoin's varint does the cutof + /// - also, that's where Bitcoin's varint does the cutoff
60-62
: Public arrays: clarify intended usage or make read-only.
EMPTY_BYTE_ARRAY
andZERO_BYTE_ARRAY
are mutable references. Consider exposing asReadOnlyMemory<byte>
or document they’re constants not to be modified.
143-166
: Performance: avoid repeated Contains lookup on int[].
indexOfListDataItems.Contains(i)
is O(n) per iteration. Convert toHashSet<int>
once for O(1) lookups.- for (var i = 0; i < dataItems.Length; i++) + var listIndexes = new HashSet<int>(indexOfListDataItems); + for (var i = 0; i < dataItems.Length; i++) { - if (indexOfListDataItems.Contains(i)) + if (listIndexes.Contains(i)) { ... } }
1-231
: Add RLP test vectors (correctness guard).Add unit tests for canonical vectors: "", 0x00, 0x7f, 0x80, short/long strings, empty list, nested lists, etc. This will lock correctness.
I can add tests for: ""→80, [ ]→c0, 0x00→00, "dog"→83646f67, ["cat","dog"]→c88363617483646f67, 1024→820400.
Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs (2)
645-651
: Chain-specific value scaling deserves a utility with docs.The 295/296 special-case division by 1e10 is non-obvious and scattered. Centralize this as Utils.ScaleNativeValueForChain(...) with a comment or reference.
Would you like me to draft that helper?
358-362
: Minor: Prefer using the shared constant for EIP-1271 magic value.You hardcode the magic bytes here but use Constants.EIP_1271_MAGIC_VALUE elsewhere. Use the constant for consistency.
- return magicValue.BytesToHex() == new byte[] { 0x16, 0x26, 0xba, 0x7e }.BytesToHex(); + return magicValue.BytesToHex() == Constants.EIP_1271_MAGIC_VALUE;Thirdweb.Tests/BaseTests.cs (1)
38-43
: Rename variable to reflect guest account.privateKeyAccount is misleading; it’s a guest wallet.
- var privateKeyAccount = await this.GetGuestAccount(); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, chainId: chainId); + var guestAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: guestAccount, chainId: chainId);Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs (1)
17-19
: Use the _chainId field instead of a hard-coded literal.Keeps tests consistent and simplifies future chain changes.
- var smartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); + var smartWallet = await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: (int)this._chainId);Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs (1)
121-124
: Minor: avoid reassigning the params array.Reassigning the params parameter is unnecessary; create a local instead for clarity.
- var requestMessage = new RpcRequestMessage(requestId, method, args = args.Where(a => a != null).ToArray()); + var filteredArgs = args.Where(a => a != null).ToArray(); + var requestMessage = new RpcRequestMessage(requestId, method, filteredArgs);Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs (3)
192-205
: Rename variable: it’s not a private-key account anymore.Avoid confusion by renaming to “guestAccount” (or just “account”).
- var privateKeyAccount = await this.GetGuestAccount(); - var receiver = await privateKeyAccount.GetAddress(); + var guestAccount = await this.GetGuestAccount(); + var receiver = await guestAccount.GetAddress(); ... - var res = await ThirdwebContract.Write(privateKeyAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data); + var res = await ThirdwebContract.Write(guestAccount, contract, "claim", 0, receiver, quantity, currency, pricePerToken, allowlistProof, data);
215-287
: Rename variable: signer is a guest wallet now.- var signer = await this.GetGuestAccount(); + var guestSigner = await this.GetGuestAccount(); ... - To = await signer.GetAddress(), - PrimarySaleRecipient = await signer.GetAddress(), + To = await guestSigner.GetAddress(), + PrimarySaleRecipient = await guestSigner.GetAddress(), ... - var signature20 = await EIP712.GenerateSignature_TokenERC20(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest20, signer); + var signature20 = await EIP712.GenerateSignature_TokenERC20(randomDomain, randomVersion, randomChainId, randomContractAddress, mintRequest20, guestSigner);(Apply similarly for 721/1155 sections.)
292-295
: Rename variable: guest vs private-key terminology.- var privateKeyAccount = await this.GetGuestAccount(); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614); + var guestAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: guestAccount, factoryAddress: "0xbf1C9aA4B1A085f7DA890a44E82B0A1289A40052", gasless: true, chainId: 421614);Thirdweb/Thirdweb.Client/ThirdwebClient.cs (1)
31-31
: Removal of ITimeoutOptions breaks consumers; add a compatibility overload or shim if not a major version bump
No internal references to ITimeoutOptions remain—this is a source-breaking change for anyone passing an ITimeoutOptions. If you’re not targeting a MAJOR version, provide an overload accepting individual timeout parameters (or a small ITimeoutOptions shim) to ease migration.Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs (1)
21-25
: Misleading variable name after wallet type switch.privateKeyWallet now holds a guest account. Rename for clarity.
Apply:
- private async Task<IThirdwebWallet> GetSmartWallet() + private async Task<IThirdwebWallet> GetSmartWallet() { - var privateKeyWallet = await this.GetGuestAccount(); - return await SmartWallet.Create(personalWallet: privateKeyWallet, chainId: 421614); + var guestAccount = await this.GetGuestAccount(); + return await SmartWallet.Create(personalWallet: guestAccount, chainId: 421614); }Thirdweb.Console/Program.cs (2)
19-22
: Avoid redundant guest logins; use IsConnected gate.Prevents re-login and reads address from wallet state.
-// Create a guest wallet -var guestWallet = await InAppWallet.Create(client, authProvider: AuthProvider.Guest); -var walletAddress = await guestWallet.LoginWithGuest(); -Console.WriteLine($"Guest Wallet address: {walletAddress}"); +// Create a guest wallet +var guestWallet = await InAppWallet.Create(client, authProvider: AuthProvider.Guest); +if (!await guestWallet.IsConnected()) +{ + _ = await guestWallet.LoginWithGuest(); +} +Console.WriteLine($"Guest Wallet address: {await guestWallet.GetAddress()}");
185-189
: Align all commented sample wallet variables toguestWallet
.Replace every instance of
myWallet
orprivateKeyWallet
in commented code samples withguestWallet
for consistent copy-paste (e.g. lines 77–80, 99–102, 109–113, 115–118, 125–136, 145–149, 164–168, 199–203, 544–548, 556–562, 572–576, 592–599, 656–660).Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs (1)
10-12
: Rename variables from privateKeyAccount → guestAccount for accuracy.Improves readability post-migration to guest wallets.
Example fix pattern:
- var privateKeyAccount = await this.GetGuestAccount(); - var smartAccount = await SmartWallet.Create(personalWallet: privateKeyAccount, gasless: true, chainId: 421614); + var guestAccount = await this.GetGuestAccount(); + var smartAccount = await SmartWallet.Create(personalWallet: guestAccount, gasless: true, chainId: 421614);Also applies to: 25-28, 35-36, 47-49, 65-73, 95-98, 131-139, 231-233, 285-290, 302-307, 322-323, 332-333, 342-343, 352-353, 362-363, 372-376
Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs (1)
1294-1303
: Poll with backoff to reduce load and improve timeout behavior.A fixed 100ms loop can hammer the bundler and trip timeouts under load.
- var queueId = response?.QueueId; - string txHash = null; - var ct = new CancellationTokenSource(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + var queueId = response?.QueueId; + string txHash = null; + var ct = new CancellationTokenSource(this.Client.FetchTimeoutOptions.GetTimeout(TimeoutType.Other)); + var delayMs = 100; try { while (txHash == null) { ct.Token.ThrowIfCancellationRequested(); - - var hashResponse = await ThirdwebBundler + var hashResponse = await ThirdwebBundler .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); + await ThirdwebTask.Delay(delayMs, ct.Token).ConfigureAwait(false); + delayMs = Math.Min(delayMs * 2, 1000); } return txHash; }Also applies to: 1312-1318
Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs (2)
64-66
: Broaden RpcRequest.Params to support both array and object formsJSON-RPC allows params to be an array or an object. Current type object[] restricts usage. Consider matching RpcRequestMessage’s flexibility.
Apply this diff:
- [JsonProperty("params")] - public object[] Params { get; set; } + [JsonProperty("params")] + [JsonConverter(typeof(RpcParameterJsonConverter))] + public object Params { get; set; }
12-19
: Minor consistency and null-safety nits
- Consider marking required fields with [JsonProperty(Required = Required.Always)] or making string properties nullable (string?) to reflect deserialization realities.
- Property naming varies (JsonRpcVersion vs Jsonrpc). Not wrong, but a consistent C# naming could reduce confusion.
Example:
- [JsonProperty("jsonrpc")] - public string JsonRpcVersion { get; private set; } + [JsonProperty("jsonrpc", Required = Required.Always)] + public string JsonRpcVersion { get; private set; }Also applies to: 28-39
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (79)
Thirdweb.Console/Program.cs
(2 hunks)Thirdweb.Tests/BaseTests.cs
(1 hunks)Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs
(0 hunks)Thirdweb.Tests/Thirdweb.Contracts/Thirdweb.Contracts.Tests.cs
(3 hunks)Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs
(6 hunks)Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs
(2 hunks)Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs
(8 hunks)Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs
(1 hunks)Thirdweb.Tests/Thirdweb.Utils/Thirdweb.Utils.Tests.cs
(1 hunks)Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs
(0 hunks)Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs
(19 hunks)Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs
(3 hunks)Thirdweb/Thirdweb.AI/ChatClient.cs
(0 hunks)Thirdweb/Thirdweb.AI/ExecutionClient.cs
(0 hunks)Thirdweb/Thirdweb.AI/SessionManager.cs
(0 hunks)Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs
(0 hunks)Thirdweb/Thirdweb.AI/ThirdwebNebula.cs
(0 hunks)Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs
(1 hunks)Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs
(1 hunks)Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs
(1 hunks)Thirdweb/Thirdweb.Client/ITimeoutOptions.cs
(0 hunks)Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs
(2 hunks)Thirdweb/Thirdweb.Client/ThirdwebClient.cs
(2 hunks)Thirdweb/Thirdweb.Client/TimeoutType.cs
(0 hunks)Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs
(0 hunks)Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs
(0 hunks)Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs
(0 hunks)Thirdweb/Thirdweb.Pay/ThirdwebPay.cs
(0 hunks)Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs
(0 hunks)Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs
(0 hunks)Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs
(0 hunks)Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs
(0 hunks)Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs
(0 hunks)Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs
(0 hunks)Thirdweb/Thirdweb.Pay/Types.Shared.cs
(0 hunks)Thirdweb/Thirdweb.RPC/RpcError.cs
(0 hunks)Thirdweb/Thirdweb.RPC/RpcRequest.cs
(0 hunks)Thirdweb/Thirdweb.RPC/RpcResponse.cs
(0 hunks)Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs
(1 hunks)Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs
(2 hunks)Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs
(2 hunks)Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs
(0 hunks)Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs
(0 hunks)Thirdweb/Thirdweb.Utils/EIP712.cs
(0 hunks)Thirdweb/Thirdweb.Utils/RLP.cs
(1 hunks)Thirdweb/Thirdweb.Utils/Utils.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs
(5 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs
(1 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs
(8 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs
(1 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs
(1 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs
(1 hunks)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs
(13 hunks)Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs
(0 hunks)Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs
(1 hunks)Thirdweb/Thirdweb.csproj
(0 hunks)nswag.json
(1 hunks)
💤 Files with no reviewable changes (51)
- Thirdweb/Thirdweb.Utils/EIP712.cs
- Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatCurrencies.cs
- Thirdweb/Thirdweb.AI/ChatClient.cs
- Thirdweb/Thirdweb.RPC/RpcError.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatQuote.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/User.cs
- Thirdweb/Thirdweb.Client/TimeoutType.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Models/UserStatus.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/Secrets.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoQuote.cs
- Thirdweb/Thirdweb.Client/ITimeoutOptions.cs
- Thirdweb/Thirdweb.Pay/Types.GetBuyHistory.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithCryptoStatus.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithFiat.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/AWS.cs
- Thirdweb/Thirdweb.csproj
- Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs
- Thirdweb/Thirdweb.Pay/Types.Shared.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatCurrencies.cs
- Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoStatus.cs
- Thirdweb/Thirdweb.Wallets/IThirdwebWallet.cs
- Thirdweb/Thirdweb.RPC/RpcRequest.cs
- Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Extensions.cs
- Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatQuote.cs
- Thirdweb/Thirdweb.AI/ExecutionClient.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/IvGenerator.cs
- Thirdweb/Thirdweb.Transactions/ThirdwebTransactionReceipt.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyWithFiatStatus.cs
- Thirdweb/Thirdweb.Pay/Types.GetBuyWithFiatStatus.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.BuyWithCrypto.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Exceptions/VerificationException.cs
- Thirdweb/Thirdweb.RPC/RpcResponse.cs
- Thirdweb/Thirdweb.Wallets/EngineWallet/EngineWallet.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Encryption/EmbeddedWallet.Cryptography.cs
- Thirdweb/Thirdweb.AI/ThirdwebNebula.Types.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Storage/LocalStorage.Types.cs
- Thirdweb/Thirdweb.Pay/ThirdwebPay.GetBuyHistory.cs
- Thirdweb/Thirdweb.AI/SessionManager.cs
- Thirdweb/Thirdweb.Indexer/ThirdwebInsight.cs
- Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Misc.cs
- Thirdweb/Thirdweb.Utils/Utils.cs
- Thirdweb.Tests/Thirdweb.AI/Thirdweb.AI.Tests.cs
- Thirdweb/Thirdweb.Wallets/ServerWallet/ServerWallet.cs
- Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.PrivateKeyWallet.Tests.cs
- Thirdweb/Thirdweb.AI/ThirdwebNebula.cs
- Thirdweb/Thirdweb.Indexer/ThirdwebInsight.Types.cs
- Thirdweb/Thirdweb.Pay/Types.GetBuyWithCryptoQuote.cs
- Thirdweb/Thirdweb.Wallets/PrivateKeyWallet/PrivateKeyWallet.cs
- Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs
🧰 Additional context used
🧬 Code graph analysis (15)
Thirdweb.Tests/BaseTests.cs (2)
Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs (18)
Task
(146-233)Task
(243-246)Task
(252-261)Task
(266-291)Task
(299-367)Task
(373-382)Task
(388-397)Task
(409-449)Task
(456-461)Task
(468-498)Task
(505-537)Task
(544-571)Task
(573-583)Task
(585-763)Task
(765-808)Task
(810-817)SmartWallet
(21-1240)SmartWallet
(101-128)Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs (2)
InAppWallet
(8-76)InAppWallet
(12-29)
Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs (1)
Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs (12)
ThirdwebTransaction
(28-521)ThirdwebTransaction
(34-38)ThirdwebTransaction
(79-83)ThirdwebTransaction
(90-94)ThirdwebTransaction
(101-105)ThirdwebTransaction
(112-116)ThirdwebTransaction
(123-127)ThirdwebTransaction
(134-138)ThirdwebTransaction
(145-149)ThirdwebTransaction
(156-160)ThirdwebTransaction
(167-171)ThirdwebTransaction
(178-182)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs (2)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs (3)
Server
(5-228)VerifyResult
(7-27)VerifyResult
(9-18)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs (5)
Server
(32-32)Server
(37-399)Server
(48-52)VerifyResult
(284-288)VerifyResult
(292-303)
Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs (1)
Thirdweb/Thirdweb.Api/ThirdwebApi.cs (1)
Newtonsoft
(47-52)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs (2)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs (1)
LocalStorage
(5-8)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.cs (3)
LocalStorage
(12-60)LocalStorage
(18-37)LocalStorageBase
(5-10)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs (1)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs (2)
VerifyResult
(284-288)VerifyResult
(292-303)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs (3)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.cs (2)
EmbeddedWallet
(3-40)EmbeddedWallet
(8-39)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs (2)
LocalStorage
(5-49)DataStorage
(31-40)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.cs (2)
LocalStorage
(12-60)LocalStorage
(18-37)
Thirdweb/Thirdweb.RPC/ThirdwebRPC.Types.cs (2)
Thirdweb/Thirdweb.Api/ThirdwebApi.cs (1)
Newtonsoft
(47-52)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs (1)
Serialize
(388-396)
Thirdweb.Console/Program.cs (1)
Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs (2)
InAppWallet
(8-76)InAppWallet
(12-29)
Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs (2)
Thirdweb/Thirdweb.Api/ThirdwebApi.cs (1)
Newtonsoft
(47-52)Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.cs (1)
ToString
(69-72)
Thirdweb/Thirdweb.Client/ThirdwebClient.cs (1)
Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs (1)
TimeoutOptions
(12-34)
Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs (3)
Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs (2)
InAppWallet
(8-76)InAppWallet
(12-29)Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs (3)
Fact
(10-15)Fact
(17-24)Fact
(26-33)Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs (18)
Task
(146-233)Task
(243-246)Task
(252-261)Task
(266-291)Task
(299-367)Task
(373-382)Task
(388-397)Task
(409-449)Task
(456-461)Task
(468-498)Task
(505-537)Task
(544-571)Task
(573-583)Task
(585-763)Task
(765-808)Task
(810-817)SmartWallet
(21-1240)SmartWallet
(101-128)
Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs (3)
Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs (1)
ThirdwebBundler
(5-146)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs (1)
EmbeddedWallet
(3-19)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs (1)
EmbeddedWallet
(3-14)
Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs (4)
Thirdweb/Thirdweb.Extensions/ThirdwebExtensions.cs (1)
CreateCallData
(36-40)Thirdweb/Thirdweb.Utils/Utils.cs (5)
HexToBytes
(128-131)Utils
(24-1206)GetEntryPointVersion
(461-475)BigInteger
(149-152)BigInteger
(396-410)Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs (1)
ThirdwebBundler
(5-146)Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.Types.cs (1)
UserOperationV6
(7-41)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs (2)
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.Types.cs (3)
Server
(5-228)VerifyResult
(7-27)VerifyResult
(9-18)Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs (1)
Server
(5-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-test-cov
🔇 Additional comments (32)
Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Extensions.cs (2)
3-3
: Namespace move to Thirdweb: verify extension type import sitesCallers importing Thirdweb.Bridge.ThirdwebBridgeExtensions must be updated to Thirdweb.ThirdwebBridgeExtensions or rely on extension method inference via using Thirdweb.
118-143
: The above script will verify whetherStatusType
includesPROCESSING
/CREATED
and ifThirdwebBridge.Status
supports cancellation. Once we have the results, I’ll update or resolve the review comment accordingly.Thirdweb/Thirdweb.Bridge/ThirdwebBridge.cs (1)
5-5
: Namespace consolidation to Thirdweb: confirm migration and public API impactThis is a breaking change for consumers using fully-qualified names. Ensure release notes, samples, and docs reflect it.
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs (2)
32-32
: API surface change: sync VerifyOAuthAsync — confirm intended and update all call sitesSwitching from Task to VerifyResult is a breaking change for any implementers/consumers. If public, consider keeping the async signature (wrapping with Task.FromResult) or provide an adapter to avoid ripple effects.
140-141
: Good consolidation via ToVerifyResultRemoving per-endpoint mapping duplication is a win. Keep this centralization.
Also applies to: 159-161, 172-173, 215-216, 239-240
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.OAuth.cs (1)
5-8
: The scripts will run and we’ll inspect:
- The file contents to confirm the signature and body.
- The definition of
VerifyOAuthAsync
to confirm its return type.- Any callers of
SignInWithOauthAsync
to ensure backward‐compat concerns.Once we have that, we’ll know whether to keep the Async name and return a
Task<VerifyResult>
or rename the method—and whether any external callers need updating.Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs (2)
1-1
: No import needed—implicit usings enabled
System.Threading.Tasks is already covered by the project’s enabled implicit global usings (<ImplicitUsings>enable</ImplicitUsings>
in the .csproj), so no additional using directive is required.
3-19
: No additional checks required for storageDirectoryPath and clientId
EcosystemWallet assigns a non-empty default storageDirectoryPath before calling new EmbeddedWallet, and ThirdwebClient guarantees a non-empty ClientId at creation—LocalStorage’s constructor will never receive null or empty values.Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs (1)
31-40
: LGTM on the serialization model and ctor assignmentsConstructor sets all backing fields and [field: DataMember] enables deserialization without setters.
Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs (2)
440-446
: Migration to CreateCallData looks good.Using CreateCallData to build calldata for setPermissionsForSigner reduces ABI coupling and is consistent with the new approach.
Also applies to: 489-495, 528-534
639-641
: Bundler/paymaster integration updates look sound; confirm env timeouts and requestId strategy.Calls now go through ThirdwebBundler with client-based timeouts. requestId is hardcoded to 1 in most paths; consider a per-call increment for tracing.
Do you want me to wire a simple monotonic requestId and add lightweight logging of method+requestId for troubleshooting?
Also applies to: 679-682, 747-755, 783-784, 796-799, 824-825, 835-836, 852-853
Thirdweb.Tests/BaseTests.cs (1)
33-36
: LGTM: guest wallet helper simplifies tests.Good abstraction; aligns the suite on InApp/guest flows.
Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.MarketplaceExtensions.Tests.cs (1)
171-175
: LGTM: guest buyer swap is correct.Approval aligns with repo-wide migration away from PrivateKeyWallet.
Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.Wallets.Tests.cs (3)
20-24
: LGTM: PersonalSignRaw now uses guest wallet.
29-33
: LGTM: PersonalSign now uses guest wallet.
118-119
: LGTM: SwitchNetwork on guest account.Matches new auth flow.
Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.ZkSmartWallet.Tests.cs (1)
10-12
: LGTM: guest personal wallet for ZK smart account.Thirdweb/Thirdweb.Wallets/SmartWallet/Thirdweb.AccountAbstraction/ThirdwebBundler.cs (2)
5-6
: Rename verification passed — no remainingBundlerClient
references found.
116-145
: Verify RpcRequestMessage/RpcResponseMessage definitions/imports.
Couldn’t locate type definitions or import directives for RpcRequestMessage or RpcResponseMessage in the repository. Ensure these types are defined in-repo or imported (e.g. via a global using) before merging.Thirdweb/Thirdweb.Client/ThirdwebClient.Types.cs (2)
12-17
: No action needed: LangVersion=latest supports C# 12 primary constructors
All three project files (Thirdweb.csproj
,Thirdweb.Console.csproj
,Thirdweb.Tests.csproj
) specify<LangVersion>latest</LangVersion>
, which includes C# 12 support.
36-56
: No duplicate TimeoutType or ITimeoutOptions found
All timeout-related types are declared only in ThirdwebClient.Types.cs; no stale enum or interface artifacts remain.Thirdweb.Tests/Thirdweb.Transactions/Thirdweb.Transactions.Tests.cs (8)
13-16
: LGTM: sample tx uses guest wallet.
51-55
: LGTM: input validation with guest wallet.
61-65
: LGTM: Create_ThrowsOnNoTo now with guest wallet.
71-75
: LGTM: Create_ThrowsOnNoWallet unaffected by guest switch.
81-85
: LGTM: chainId zero case unchanged; guest wallet OK.
163-168
: LGTM: signing with SmartWallet backed by guest wallet.
330-337
: LGTM: EstimateGasFees on chain 250 with guest wallet.Good coverage for non-zk path.
363-376
: LGTM: simulate via SmartWallet backed by guest wallet.Assertion tolerates intrinsic gas variance.
Thirdweb/Thirdweb.Transactions/ThirdwebTransaction.Types.cs (1)
224-323
: Receipt type relocation approved. Consolidating ThirdwebTransactionReceipt here is fine; JSON bindings match common ETH receipt fields, and no duplicate definitions remain.Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs (2)
121-121
: Good switch to ThirdwebBundler for delegation contract.Centralizing bundler RPCs behind ThirdwebBundler aligns with the new timeout options and error handling.
305-306
: Ensure handling for missing enclave wallets
Hard‐fail on users without an enclave wallet is a breaking behavior change—verify every caller now catches the InvalidOperationException and surfaces a clear remediation path (re-auth/migration). Consider replacing the generic exception with a dedicated MissingEnclaveWalletException for precise handling and telemetry.
@@ -64,7 +64,7 @@ | |||
"generateImmutableDictionaryProperties": false, | |||
"jsonConverters": null, | |||
"anyType": "object", | |||
"output": "Thirdweb/Thirdweb.Api/GeneratedClient.cs" | |||
"output": "Thirdweb/Thirdweb.Api/ThirdwebApi.cs" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Path rename: verify no stale references to GeneratedClient.cs and avoid duplicate type compilation
Changing the generated file to Thirdweb/Thirdweb.Api/ThirdwebApi.cs is fine. Please ensure:
- The old GeneratedClient.cs is removed/excluded from all projects.
- No build/pipeline scripts or docs reference GeneratedClient.cs.
- No .csproj explicitly includes/excludes the old path.
Run this to confirm and surface any remaining references:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Check for old/new generated files:"
fd -t f -a 'GeneratedClient.cs|ThirdwebApi.cs' || true
echo -e "\nSearch for references to the old file name:"
rg -nP --hidden --glob '!.git/' 'GeneratedClient\.cs' -C2 || true
echo -e "\nSearch for explicit Compile Include entries in project files:"
fd -t f -e csproj -e props -e targets -x rg -nP 'GeneratedClient\.cs|ThirdwebApi\.cs' -n {} || true
Length of output: 347
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching for stale references to 'GeneratedClient.cs':"
rg -nF --no-ignore 'GeneratedClient.cs' -C1 || true
echo -e "\nSearching for explicit <Compile Include> entries for GeneratedClient.cs in csproj files:"
rg -nP --no-ignore '<Compile\s+Include=.*GeneratedClient\.cs' -n -g '**/*.csproj' || true
echo -e "\nSearching for references in docs and scripts (md, yml, yaml, sh, ps1, json):"
rg -nF --no-ignore 'GeneratedClient.cs' -g '**/*.{md,yml,yaml,sh,ps1,json}' -C1 || true
echo -e "\nVerifying new generated file 'ThirdwebApi.cs' exists:"
rg -nF --no-ignore 'ThirdwebApi.cs' -C1 || true
echo -e "\nSearching for explicit <Compile Include> entries for ThirdwebApi.cs in csproj files:"
rg -nP --no-ignore '<Compile\s+Include=.*ThirdwebApi\.cs' -n -g '**/*.csproj' || true
Length of output: 1330
Update stale references to GeneratedClient.cs
– codecov.yml still lists "Thirdweb/Thirdweb.Api/GeneratedClient.cs"
(line 4); update or remove it
– tw.bat contains checks and deletion commands for Thirdweb\Thirdweb.Api\GeneratedClient.cs
(lines 21–25, 58–60, 84–86); point these at ThirdwebApi.cs
instead
🤖 Prompt for AI Agents
In nswag.json around line 67, the output filename was changed to
"Thirdweb/Thirdweb.Api/ThirdwebApi.cs" but other repo files still reference the
old GeneratedClient.cs; update codecov.yml (replace
"Thirdweb/Thirdweb.Api/GeneratedClient.cs" at line ~4 with
"Thirdweb/Thirdweb.Api/ThirdwebApi.cs" or remove the entry) and edit tw.bat
(replace references and deletion/check paths at lines ~21–25, ~58–60, ~84–86 to
point to Thirdweb\Thirdweb.Api\ThirdwebApi.cs, ensuring path separators match
the script) so all tooling and CI reference the new ThirdwebApi.cs filename
consistently.
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()) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Ensure GetGuestAccount returns a connected wallet.
These tests call GetAddress() or sign immediately. If GetGuestAccount doesn’t perform LoginWithGuest, these will flake.
Check BaseTests.GetGuestAccount implementation:
Expected: it creates InAppWallet with AuthProvider.Guest and either is already connected or calls LoginWithGuest before returning. If not, update helper to connect.
I can patch BaseTests to guarantee connection on return if needed.
Also applies to: 1531-1533, 1566-1568, 1699-1701, 1736-1738
🏁 Script executed:
#!/bin/bash
rg -n -C4 'async\s+Task<\s*IThirdwebWallet\s*>\s*GetGuestAccount' && rg -n -C2 'LoginWithGuest|IsConnected\(\)' Thirdweb.Tests
Length of output: 1963
Ensure GetGuestAccount
connects before returning
Modify BaseTests.GetGuestAccount
to call LoginWithGuest
on the newly created wallet so any subsequent GetAddress()
or signing calls won’t flake:
public async Task<IThirdwebWallet> GetGuestAccount()
{
- return await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest);
+ var wallet = await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest);
+ await wallet.LoginWithGuest();
+ return wallet;
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
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()) }; | |
public async Task<IThirdwebWallet> GetGuestAccount() | |
{ | |
var wallet = await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest); | |
await wallet.LoginWithGuest(); | |
return wallet; | |
} |
🤖 Prompt for AI Agents
In Thirdweb.Tests/Thirdweb.Extensions/Thirdweb.Extensions.Tests.cs around lines
1423-1425, the tests call GetGuestAccount() but that helper must ensure the
created wallet is connected; update BaseTests.GetGuestAccount to call and await
LoginWithGuest (or the equivalent connect/login method) on the new wallet
instance before returning it so subsequent GetAddress() or signing calls are
reliable; ensure the call is awaited and surface or throw any errors if login
fails.
_ = 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() }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Guarantee guest account is connected in helper to prevent null addresses.
Multiple tests assume immediate address/signing ability. If GetGuestAccount doesn’t ensure LoginWithGuest, these can intermittently fail.
Inspect helper and enforce connect if missing:
If not connected, adjust BaseTests:
public async Task<IThirdwebWallet> GetGuestAccount() {
var wallet = await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest);
if (!await wallet.IsConnected()) { _ = await wallet.LoginWithGuest(); }
return wallet;
}
Also applies to: 322-323, 332-333, 342-343, 352-353, 362-363, 372-376
🏁 Script executed:
#!/bin/bash
rg -n -C3 'async\s+Task<\s*IThirdwebWallet\s*>\s*GetGuestAccount' Thirdweb.Tests && rg -n -C2 'LoginWithGuest|IsConnected\(\)' Thirdweb.Tests
Length of output: 1894
Ensure guest wallet is connected before use
In Thirdweb.Tests/BaseTests.cs
(lines 33–36), GetGuestAccount
must call LoginWithGuest()
if the wallet isn’t already connected to avoid null-address failures in downstream tests. For example:
public async Task<IThirdwebWallet> GetGuestAccount() {
- return await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest);
+ var wallet = await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest);
+ if (!await wallet.IsConnected()) {
+ await wallet.LoginWithGuest();
+ }
+ return wallet;
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
_ = 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() }); | |
public async Task<IThirdwebWallet> GetGuestAccount() { | |
var wallet = await InAppWallet.Create(this.Client, authProvider: AuthProvider.Guest); | |
if (!await wallet.IsConnected()) { | |
await wallet.LoginWithGuest(); | |
} | |
return wallet; | |
} |
🤖 Prompt for AI Agents
In Thirdweb.Tests/BaseTests.cs around lines 33–36 and usage in
Thirdweb.Tests/Thirdweb.Wallets/Thirdweb.SmartWallet.Tests.cs lines 95–98, the
guest account may be returned before the wallet is connected causing
null-address failures; update GetGuestAccount to check whether the guest wallet
is connected and, if not, call and await LoginWithGuest() (or the equivalent
connect method) before returning the account so downstream tests using the
returned account can safely call GetAddress()/SendTransaction.
@@ -1,7 +1,7 @@ | |||
using System.Numerics; | |||
using Newtonsoft.Json; | |||
|
|||
namespace Thirdweb.Bridge; | |||
namespace Thirdweb; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Namespace consolidation to Thirdweb: confirm v3-breaking API and migration plan
This rename breaks fully-qualified type names. Ensure downstream code, samples, and docs are updated, and call out the breaking change in the v3 changelog. If you want to help users, consider temporary shim types in the old namespace marked [Obsolete] for a deprecation window.
Run to spot any lingering references:
🏁 Script executed:
#!/bin/bash
# Find old namespace usages
rg -nP 'namespace\s+Thirdweb\.Bridge\b|Thirdweb\.Bridge\.' -C2
Length of output: 0
Document v3-breaking namespace consolidation from Thirdweb.Bridge to Thirdweb
Verified no residual Thirdweb.Bridge
references. Ensure all downstream code, samples, and documentation use namespace Thirdweb
, call out this breaking change in the v3 changelog, and (optionally) provide [Obsolete]
shim types in the old Thirdweb.Bridge
namespace for a deprecation window.
🤖 Prompt for AI Agents
In Thirdweb/Thirdweb.Bridge/ThirdwebBridge.Types.cs around line 4, the file
currently uses namespace Thirdweb (consolidation from Thirdweb.Bridge), but the
project must document and propagate this breaking change: update all downstream
code, sample projects and documentation to reference namespace Thirdweb instead
of Thirdweb.Bridge; add a clear v3 changelog entry describing the breaking
change and migration notes; optionally add a small shim file under the old
Thirdweb.Bridge namespace that defines obsolete wrapper types (annotated with
[Obsolete] and forwarding to the new Thirdweb types) to provide a short
deprecation window while tests and samples are updated.
revertMsg = rpcResponse.Error.Data.Type == JTokenType.String ? rpcResponse.Error.Data.ToString() : JsonConvert.SerializeObject(rpcResponse.Error.Data); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Defensive cast for Error.Data before accessing JToken.Type.
If Data is not a JToken, accessing .Type will throw. Safe-cast first and fall back to ToString/serialize.
- revertMsg = rpcResponse.Error.Data.Type == JTokenType.String ? rpcResponse.Error.Data.ToString() : JsonConvert.SerializeObject(rpcResponse.Error.Data);
+ if (rpcResponse.Error.Data is JToken jt)
+ {
+ revertMsg = jt.Type == JTokenType.String ? jt.ToString() : jt.ToString(Formatting.None);
+ }
+ else
+ {
+ revertMsg = rpcResponse.Error.Data?.ToString() ?? string.Empty;
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
revertMsg = rpcResponse.Error.Data.Type == JTokenType.String ? rpcResponse.Error.Data.ToString() : JsonConvert.SerializeObject(rpcResponse.Error.Data); | |
} | |
if (rpcResponse.Error.Data is JToken jt) | |
{ | |
// For JToken data, emit the raw string if it's already a string token, | |
// otherwise output its compact JSON representation. | |
revertMsg = jt.Type == JTokenType.String | |
? jt.ToString() | |
: jt.ToString(Formatting.None); | |
} | |
else | |
{ | |
// For non-JToken (or null), fall back to the object's ToString (or empty). | |
revertMsg = rpcResponse.Error.Data?.ToString() ?? string.Empty; | |
} |
🤖 Prompt for AI Agents
In Thirdweb/Thirdweb.RPC/ThirdwebRPC.cs around lines 210-211, the code assumes
rpcResponse.Error.Data is a JToken and accesses .Type directly which can throw
if Data is not a JToken; change to safely cast Data to JToken (e.g. var
dataToken = rpcResponse.Error.Data as JToken), then if dataToken is non-null use
dataToken.Type to decide whether to call ToString() or
JsonConvert.SerializeObject(dataToken), otherwise fall back to calling
ToString() on rpcResponse.Error.Data or
JsonConvert.SerializeObject(rpcResponse.Error.Data) as appropriate and handle
nulls to avoid exceptions.
internal override VerifyResult VerifyOAuthAsync(string authResultStr) | ||
{ | ||
var authResult = JsonConvert.DeserializeObject<AuthResultType>(authResultStr); | ||
return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false); | ||
return this.ToVerifyResult(authResult); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
OAuth verify now trusts raw JSON — add validation and error handling
authResultStr is untrusted input. Handle malformed JSON and missing fields to avoid NREs and clearer errors.
Apply:
- internal override VerifyResult VerifyOAuthAsync(string authResultStr)
- {
- var authResult = JsonConvert.DeserializeObject<AuthResultType>(authResultStr);
- return this.ToVerifyResult(authResult);
- }
+ internal override VerifyResult VerifyOAuthAsync(string authResultStr)
+ {
+ if (string.IsNullOrWhiteSpace(authResultStr))
+ {
+ throw new ArgumentException("Empty OAuth authResult payload.", nameof(authResultStr));
+ }
+ AuthResultType authResult;
+ try
+ {
+ authResult = JsonConvert.DeserializeObject<AuthResultType>(authResultStr);
+ }
+ catch (JsonException ex)
+ {
+ throw new InvalidOperationException("Failed to parse OAuth authResult payload.", ex);
+ }
+ if (authResult?.StoredToken == null)
+ {
+ throw new InvalidOperationException("Invalid OAuth payload: missing StoredToken.");
+ }
+ return this.ToVerifyResult(authResult);
+ }
Is authResultStr guaranteed to originate from a trusted Thirdweb redirect (not caller-supplied)? If not, consider a server-side verification round-trip.
Validate and handle errors in VerifyOAuthAsync (Server.cs:284-288)
Guard against empty or whitespace authResultStr, catch JsonConvert.DeserializeObject failures, and verify required fields (e.g. authResult.StoredToken) before calling ToVerifyResult to avoid null‐reference exceptions and surface clear errors. Also confirm that authResultStr is only ever set from a trusted OAuth redirect—or implement a server-side verification round-trip if it can be caller-supplied.
🤖 Prompt for AI Agents
In
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs
around lines 284-288, VerifyOAuthAsync currently deserializes authResultStr
without validation or error handling which can cause null-reference exceptions
and unclear failures; update the method to first guard against
null/empty/whitespace authResultStr and return a failed VerifyResult when
invalid, wrap JsonConvert.DeserializeObject in a try/catch to handle and log
deserialization errors and return a clear failure VerifyResult on exception,
validate that the deserialized authResult and required fields (e.g.
authResult.StoredToken) are present before calling ToVerifyResult and return
explicit errors if missing, and if authResultStr can be supplied by callers
ensure you perform a server-side verification round-trip or verify the OAuth
redirect/source before trusting the payload.
private VerifyResult ToVerifyResult(AuthResultType authResult) | ||
{ | ||
var webExchangeResult = await this.FetchCognitoIdTokenAsync(authToken).ConfigureAwait(false); | ||
return await AWS.GenerateDataKey(webExchangeResult.IdentityId, webExchangeResult.Token, this._httpClient).ConfigureAwait(false); | ||
} | ||
|
||
private async Task<VerifyResult> 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, this._httpClient).ConfigureAwait(false); | ||
|
||
var jsonSerializer = new JsonSerializer(); | ||
var payload = jsonSerializer.Deserialize<RecoverySharePasswordResponse>(new JsonTextReader(new StreamReader(responsePayload))); | ||
payload = jsonSerializer.Deserialize<RecoverySharePasswordResponse>(new JsonTextReader(new StringReader(payload.Body))); | ||
return new VerifyResult( | ||
authResult.StoredToken.AuthProvider, | ||
authResult.StoredToken.IsNewUser, | ||
authToken, | ||
authResult.StoredToken.CookieString, | ||
authResult.StoredToken.AuthDetails.UserWalletId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Critical: Using CookieString as AuthToken likely breaks Authorization Bearer and downstream calls
AuthToken from ToVerifyResult is used by SendHttpWithAuthAsync as: "Authorization: Bearer embedded-wallet-token:{authToken}". A cookie string is not a bearer token and will likely fail. Other flows (VerifyJwtAsync/VerifyAuthEndpointAsync) return a JWT string. Use JwtToken for consistency.
Apply:
- authResult.StoredToken.CookieString,
+ authResult.StoredToken.JwtToken,
Follow-ups:
- If CookieString must also be persisted, expose/store it separately (e.g., add property or set an internal Cookie header when ShouldStoreCookieString is true).
Run to locate AuthToken consumers and ensure bearer expectations:
🏁 Script executed:
#!/bin/bash
rg -n -C3 '\bAuthToken\b' --type cs
rg -n -C2 'embedded-wallet-token:' --type cs
Length of output: 13930
🏁 Script executed:
#!/bin/bash
# Locate AuthResultType definition to inspect StoredToken structure
rg -n 'AuthResultType' -C5 --type cs Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs
# Locate StoredToken references within AuthResultType
rg -n 'StoredToken' -C5 --type cs Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs
# Verify presence of JwtToken property in the codebase
rg -n 'JwtToken' -C5 --type cs
Length of output: 6791
Use JWT for Bearer Authorization
In Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs
’s ToVerifyResult
(around line 297), replace the cookie string with the JWT so downstream calls get a valid bearer token:
- authResult.StoredToken.CookieString,
+ authResult.StoredToken.JwtToken,
If you still need the cookie value, surface it separately (e.g. add a dedicated property or header).
🤖 Prompt for AI Agents
In
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Authentication/Server.cs
around lines 292 to 298, change the value passed for the token in VerifyResult
from the cookie string to the JWT/bearer token so downstream calls receive a
valid Authorization: Bearer token; specifically replace
authResult.StoredToken.CookieString with the JWT property on StoredToken (e.g.
StoredToken.Jwt or StoredToken.AccessToken), and if the cookie value still must
be preserved, add a separate property to VerifyResult (or another header) to
carry the cookie rather than overloading the token field.
[DataContract] | ||
private class Storage | ||
{ | ||
[DataMember] | ||
internal DataStorage Data { get; set; } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Make Storage.Data nullable (+ align base/override types)
Data
can legitimately be absent. Mark it nullable and align LocalStorageBase
/overrides accordingly to avoid NRT warnings and accidental assumptions.
Apply here:
- internal DataStorage Data { get; set; }
+ internal DataStorage? Data { get; set; }
Also update the base and override (in LocalStorageBase and LocalStorage.cs):
- internal abstract LocalStorage.DataStorage Data { get; }
- internal abstract Task SaveDataAsync(LocalStorage.DataStorage data);
+ internal abstract LocalStorage.DataStorage? Data { get; }
+ internal abstract Task SaveDataAsync(LocalStorage.DataStorage? data);
- internal override DataStorage Data => this._storage.Data;
+ internal override DataStorage? Data => this._storage.Data;
- internal override Task SaveDataAsync(DataStorage data)
+ internal override Task SaveDataAsync(DataStorage? data)
Verify impact:
🏁 Script executed:
#!/bin/bash
rg -n '\b\.Data\b' Thirdweb -g '*.cs' -C2
rg -nP 'SaveDataAsync\s*\(' Thirdweb -g '*.cs' -C2
Length of output: 18509
Make Storage.Data nullable and update LocalStorage signatures & GetSessionData
- LocalStorage.Types.cs:
- internal DataStorage Data { get; set; } + internal DataStorage? Data { get; set; }
- LocalStorageBase (Abstract):
- internal abstract LocalStorage.DataStorage Data { get; } - internal abstract Task SaveDataAsync(LocalStorage.DataStorage data); + internal abstract LocalStorage.DataStorage? Data { get; } + internal abstract Task SaveDataAsync(LocalStorage.DataStorage? data);
- LocalStorage override:
- internal override DataStorage Data => this._storage.Data; - internal override Task SaveDataAsync(DataStorage data) + internal override DataStorage? Data => this._storage.Data; + internal override Task SaveDataAsync(DataStorage? data)
- EmbeddedWallet.Misc.cs: change
to align the nullable return of
- internal LocalStorage.DataStorage GetSessionData() + internal LocalStorage.DataStorage? GetSessionData()
this._localStorage.Data
.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
[DataContract] | |
private class Storage | |
{ | |
[DataMember] | |
internal DataStorage Data { get; set; } | |
} | |
[DataContract] | |
private class Storage | |
{ | |
[DataMember] | |
internal DataStorage? Data { get; set; } | |
} |
🤖 Prompt for AI Agents
In
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet.Storage/LocalStorage.Types.cs
around lines 43-48, change the Storage.Data property to be nullable (e.g.
DataStorage?) and then propagate that nullability: update the abstract
LocalStorageBase method/property signatures to return/accept nullable
DataStorage, update the concrete LocalStorage override implementations to match
the nullable signatures and handle null appropriately, and modify
EmbeddedWallet.Misc.cs where this._localStorage.Data is used so callers accept
and handle a possibly null return (adjust types and add null checks or fallback
logic as needed).
internal async void UpdateSessionData(LocalStorage.DataStorage data) | ||
{ | ||
await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid async void; return Task to propagate errors and allow awaiting
async void
hides exceptions and is not awaitable. Return Task
and forward the inner task.
Apply:
- internal async void UpdateSessionData(LocalStorage.DataStorage data)
- {
- await this._localStorage.SaveDataAsync(data).ConfigureAwait(false);
- }
+ internal Task UpdateSessionData(LocalStorage.DataStorage data)
+ {
+ return this._localStorage.SaveDataAsync(data);
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
internal async void UpdateSessionData(LocalStorage.DataStorage data) | |
{ | |
await this._localStorage.SaveDataAsync(data).ConfigureAwait(false); | |
} | |
internal Task UpdateSessionData(LocalStorage.DataStorage data) | |
{ | |
return this._localStorage.SaveDataAsync(data); | |
} |
🤖 Prompt for AI Agents
In
Thirdweb/Thirdweb.Wallets/InAppWallet/Thirdweb.EWS/EmbeddedWallet/EmbeddedWallet.Misc.cs
around lines 10-13, the method UpdateSessionData is declared async void which
hides exceptions and cannot be awaited; change its signature to return Task
(i.e., Task UpdateSessionData(...)) and remove the async/await by returning the
inner SaveDataAsync call (or if awaiting is needed keep async and return Task)
so callers can await and exceptions propagate.
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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NullRef risk when no initCode: FactoryData computed from null.
When the account is already deployed, factoryData is null; calling HexToBytes() will throw. Default to empty bytes and a zero address.
- Factory = factory,
- FactoryData = factoryData.HexToBytes(),
+ Factory = string.IsNullOrEmpty(factory) ? Constants.ADDRESS_ZERO : factory,
+ FactoryData = string.IsNullOrEmpty(factoryData) ? Array.Empty<byte>() : factoryData.HexToBytes(),
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
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, | |
Sender = this._accountContract.Address, | |
Nonce = await this.GetNonce().ConfigureAwait(false), | |
- Factory = factory, | |
Factory = string.IsNullOrEmpty(factory) | |
? Constants.ADDRESS_ZERO | |
: factory, | |
FactoryData = string.IsNullOrEmpty(factoryData) | |
? Array.Empty<byte>() | |
: factoryData.HexToBytes(), | |
CallData = executeInput.HexToBytes(), | |
CallGasLimit = 0, | |
VerificationGasLimit = 0, |
🤖 Prompt for AI Agents
In Thirdweb/Thirdweb.Wallets/SmartWallet/SmartWallet.cs around lines 703-709,
the code calls HexToBytes() on factoryData which can be null when the account is
already deployed; change the assignment to guard against null by using an empty
byte[] when factoryData is null or empty and set Factory to the zero address in
that case. Specifically, only call HexToBytes() when factoryData is
non-null/non-empty and otherwise set FactoryData to a new empty byte array and
Factory to the zero address; keep existing values when factoryData is present.
WIP
PR-Codex overview
This PR primarily focuses on the removal of several files and refactoring of existing code within the
Thirdweb
library, including changes to wallet management, transaction handling, and API response structures.Detailed summary
Thirdweb.RPC
,Thirdweb.AI
,Thirdweb.Pay
, andThirdweb.Wallets
.ThirdwebBridge
andThirdwebBridgeExtensions
namespaces.RpcRequest
andRpcResponse
structures.SignInWithOauthAsync
method to return aVerifyResult
directly.IThirdwebWallet
.ThirdwebTransactionReceipt
class for transaction details.TimeoutOptions
class to remove interface implementation.Summary by CodeRabbit
New Features
Refactor
Removals
Tests