[MNY-233] SDK: Add Last Used badge in Connect UI (thirdweb-dev#8631)#601
[MNY-233] SDK: Add Last Used badge in Connect UI (thirdweb-dev#8631)#601Dargon789 merged 11 commits intoDargon789:mainfrom
Conversation
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Joaquim Verges <joaquim.verges@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
@joaquim-verges is attempting to deploy a commit to the Foundry development Team on Vercel. A member of the Team first needs to authorize it. |
Reviewer's GuideImplements "Last Used" surfacing across the Connect UI and social auth flows, adds Base Account SDK wallet integration, upgrades x402 payment protocol handling to support version 2 with header-based signatures, adds EIP-5792 raw call status support and fallbacks for zkSync gas estimation, and wires corresponding docs, examples, tests, and changelog/version bumps. Class diagram for Base Account SDK wallet and EIP-5792 extensionsclassDiagram
class Wallet {
<<interface>>
+string id
+Account getAccount()
+Chain getChain()
+Promise~Account~ connect(options)
+Promise~Account~ autoConnect(options)
+Promise void disconnect()
+Promise void switchChain(chain)
+subscribe(event, listener)
}
class Account {
<<interface>>
+string address
+Promise sendTransaction(options)
+Promise~string~ signMessage(message)
+Promise~string~ signTypedData(typedData)
+Promise sendCalls(options)
+Promise~GetCallsStatusResponse~ getCallsStatus(options)
+Promise~GetCallsStatusRawResponse~ getCallsStatusRaw(options)
+Promise~WalletCapabilitiesResult~ getCapabilities(options)
}
class BaseAccountWalletCreationOptions {
+AppMetadata appMetadata
+Chain[] chains
}
class BaseAccountSDKWalletConnectionOptions {
+ThirdwebClient client
+Chain chain
}
class BaseAccountWallet {
<<Wallet "org.base.account">>
+string id
+BaseAccountWalletCreationOptions getConfig()
+Promise~Account~ connect(options)
+Promise~Account~ autoConnect(options)
+Promise void disconnect()
+Promise void switchChain(chain)
+Account getAccount()
+Chain getChain()
}
class ProviderInterface {
<<from @base-org/account>>
+Promise~unknown~ request(request)
+on(event, listener)
+off(event, listener)
+Promise void disconnect()
}
class GetCallsStatusRawResponse {
+string id
+string chainId
+boolean atomic
+int status
+Receipt[] receipts
+string version
}
class CoinbaseAccount {
<<EIP-1193 wallet>>
+Promise~GetCallsStatusRawResponse~ getCallsStatusRaw(options)
}
class InjectedAccount {
<<EIP-1193 wallet>>
+Promise~GetCallsStatusRawResponse~ getCallsStatusRaw(options)
}
class SmartAccount {
<<Smart wallet>>
+Promise~GetCallsStatusRawResponse~ getCallsStatusRaw(options)
}
class Minimal7702Account {
<<EIP-7702 account>>
+Promise~GetCallsStatusRawResponse~ getCallsStatusRaw(options)
}
class EnclaveWalletAccount {
<<In-app enclave>>
+Promise~GetCallsStatusRawResponse~ getCallsStatusRaw(options)
}
class ToEip1193Provider {
+EIP1193Provider toProvider(options)
}
Wallet <|.. BaseAccountWallet
Account <.. BaseAccountWallet : uses
ProviderInterface <.. BaseAccountWallet : providerFactory
GetCallsStatusRawResponse <.. Account
Account <|.. CoinbaseAccount
Account <|.. InjectedAccount
Account <|.. SmartAccount
Account <|.. Minimal7702Account
Account <|.. EnclaveWalletAccount
ToEip1193Provider --> Account : calls getCallsStatusRaw
Flow diagram for Last Used wallet and social auth persistenceflowchart TD
subgraph Storage
S1[localStorage
LAST_USED_WALLET_ID]
S2[localStorage
LAST_AUTH_PROVIDER]
end
subgraph ConnectModalOpen
O1[WalletSelector] --> O2[getLastUsedWalletId]
O2 --> S1
O1 --> O3[sortWallets]
O3 -->|prioritize installed| O4
O3 -->|then last used id| O5
O5 --> WalletList
WalletList -->|render| W1[WalletEntryButton]
W1 -->|if wallet.id === lastUsedId| W2[badge = Last used]
O1 --> C1[Connect a wallet button]
C1 -->|prop lastUsedBadge
when lastUsedId is non inApp non ecosystem| C2[Show LastUsedBadge]
end
subgraph SocialAuthOptions
SA1[ConnectWalletSocialOptions]
SA1 --> SA2[getLastUsedWalletId]
SA1 --> SA3[getLastUsedSocialAuth]
SA2 --> S1
SA3 --> S2
SA1 --> SA4[_authOptions]
SA4 -->|if wallet.id == lastUsedId
and lastUsedSocialAuth set| SA5[Sort auth options
to put last used first]
SA5 --> SA6[Render social buttons/InputSelectionUI]
SA6 -->|if wallet.id and method match last used| SA7[Show LastUsedBadge]
end
subgraph OnSuccessfulConnect
C10[ConnectionManager.connect]
C10 --> C11[Set LAST_ACTIVE_EOA_ID]
C10 --> C12[Set LAST_USED_WALLET_ID]
C11 --> S1
C12 --> S1
SocialLoginSuccess --> C13[setLastAuthProvider]
C13 --> S2
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The new "last used" wallet tracking mixes AsyncStorage (manager writes LAST_USED_WALLET_ID) with direct window.localStorage access in the Connect UI helpers; if a custom storage adapter is used, the UI badges/sorting will silently diverge from the actual connection state—consider routing reads through the same AsyncStorage abstraction or clearly constraining this feature to localStorage-backed setups.
- The Base Account SDK provider is effectively a global singleton with configuration taken only on first use; it may be worth documenting or enforcing this more strongly (e.g. by throwing rather than just warning on conflicting create options) to help consumers avoid subtle misconfigurations when they accidentally create multiple Base Account wallets with different settings.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new "last used" wallet tracking mixes AsyncStorage (manager writes LAST_USED_WALLET_ID) with direct window.localStorage access in the Connect UI helpers; if a custom storage adapter is used, the UI badges/sorting will silently diverge from the actual connection state—consider routing reads through the same AsyncStorage abstraction or clearly constraining this feature to localStorage-backed setups.
- The Base Account SDK provider is effectively a global singleton with configuration taken only on first use; it may be worth documenting or enforcing this more strongly (e.g. by throwing rather than just warning on conflicting create options) to help consumers avoid subtle misconfigurations when they accidentally create multiple Base Account wallets with different settings.
## Individual Comments
### Comment 1
<location> `packages/thirdweb/src/x402/common.ts:84-93` </location>
<code_context>
args: PaymentArgs,
): Promise<GetPaymentRequirementsResult | PaymentRequiredResult> {
- const { facilitator, routeConfig = {}, paymentData } = args;
+ const { facilitator, routeConfig = {}, paymentData, resourceUrl } = args;
const { errorMessages } = routeConfig;
+ // facilitator.accepts() returns v1 format from API - extract payment requirements
const paymentRequirementsResult = await facilitator.accepts(args);
+ const paymentRequirements = paymentRequirementsResult.responseBody.accepts;
- // Check for payment header, if none, return the payment requirements
+ // Check for payment header, if none, return the payment requirements in v2 format (default)
if (!paymentData) {
- return paymentRequirementsResult;
+ return formatPaymentRequiredResponseV2(
+ paymentRequirements,
+ "Payment required",
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Respect requested x402 version when deciding v1 vs v2 response format
`decodePaymentRequest` now receives `x402Version`, but still always returns a v2-style `PaymentRequiredResult` when `paymentData` is missing and on decode errors. This prevents v1 callers from getting a v1-formatted response. Use `args.x402Version` (with the existing default) to choose `formatPaymentRequiredResponseV1` vs `formatPaymentRequiredResponseV2` in the `!paymentData` and decode-error paths so the response format matches the requested protocol version.
Suggested implementation:
```typescript
export async function decodePaymentRequest(
args: PaymentArgs,
): Promise<GetPaymentRequirementsResult | PaymentRequiredResult> {
const {
facilitator,
routeConfig = {},
paymentData,
resourceUrl,
x402Version,
} = args;
const { errorMessages } = routeConfig;
// facilitator.accepts() returns v1 format from API - extract payment requirements
const paymentRequirementsResult = await facilitator.accepts(args);
const paymentRequirements = paymentRequirementsResult.responseBody.accepts;
// Check for payment header, if none, return the payment requirements in the requested x402 format
if (!paymentData) {
const useV1Format = x402Version === "1"; // respects requested x402 version
return useV1Format
? formatPaymentRequiredResponseV1(
paymentRequirements,
"Payment required",
resourceUrl,
)
: formatPaymentRequiredResponseV2(
paymentRequirements,
"Payment required",
resourceUrl,
);
}
```
1. Update the decode-error path in `decodePaymentRequest` (inside the `catch` around `decodePayment(paymentData)`) to also branch on `x402Version` in the same way as the `!paymentData` path, returning `formatPaymentRequiredResponseV1(...)` for v1 callers and `formatPaymentRequiredResponseV2(...)` otherwise.
2. If the codebase already defines canonical x402 version constants or uses a different string for v1 (e.g. `"v1"` or `"0.1"`), replace the hard-coded `"1"` check with that existing convention, or use a helper such as `isV1x402Version(x402Version)` if one exists.
3. If there is an existing default x402 version (e.g. on `PaymentArgs` or a shared config), ensure that `x402Version` is always set before reaching this function, or derive the default here to keep behavior consistent across the codebase.
</issue_to_address>
### Comment 2
<location> `packages/thirdweb/src/wallets/in-app/web/lib/get-url-token.ts:28-31` </location>
<code_context>
const walletId = params.get("walletId") as WalletId | undefined;
const authProvider = params.get("authProvider") as AuthOption | undefined;
const authCookie = params.get("authCookie") as string | undefined;
+ const authFlow = params.get("authFlow") as "connect" | "link" | undefined;
if ((authCookie || authResultString) && walletId) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Align `authFlow` runtime values with the declared return type of `getUrlToken`
`params.get("authFlow")` can return `null`, but it’s cast to `"connect" | "link" | undefined` and the function type is `authFlow?: "connect" | "link";` (no `null`), while tests now expect `authFlow: null`. This type/runtime mismatch can confuse consumers. Consider normalizing non-matching values to `undefined` before returning (e.g. `const raw = params.get("authFlow"); const authFlow = raw === "connect" || raw === "link" ? raw : undefined;`) and update tests/types accordingly, or explicitly allow `null` in the type if that’s intentional.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Summary of ChangesHello @Dargon789, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly upgrades the SDK's wallet connectivity and payment processing capabilities. It integrates a new wallet connector for the Base Account SDK and refines the user interface of the Connect Wallet component with a 'Last Used' badge. Additionally, the x402 payment protocol has been advanced to version 2, introducing more flexible payment data handling and ensuring better compatibility with various blockchain environments, including improved fallback for zkSync transactions. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces several new features and improvements across the thirdweb SDK and related applications. Key changes include the integration of the Base Account SDK, adding support for linking accounts with redirect mode, and enhancing the x402 payment protocol to support a v2 header-based format. UI improvements have been made to various widgets, such as the BuyWidget, TransactionWidget, SwapWidget, and BridgeWidget, including new props to disable token selection/amount editing, more reliable chain lists, token selection UX enhancements, and the addition of a 'Last Used' badge in the Connect UI to highlight recently used wallets and social authentication methods. The update also adds support for the Etherlink Shadownet testnet chain. Internally, there are updates to EIP-5792 handling for getCallsStatus and getCallsStatusRaw across different wallet types, and a fallback mechanism for zkSync gas fee estimation when zks_estimateFee is unavailable. Documentation and example code have been updated to reflect these changes, particularly for the x402 header and Base Account SDK integration.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Head branch was pushed to by a user without write access
Summary by Sourcery
Introduce Base Account SDK wallet integration, enhance Connect UI with last-used indicators, and extend x402 and EIP-5792 payment and calls support while improving zkSync gas estimation fallbacks and examples.
New Features:
Bug Fixes:
Enhancements:
Build:
Documentation:
Tests:
Chores: