-
Notifications
You must be signed in to change notification settings - Fork 0
docs(wcp): custom theming for data collection form + structure cleanup #74
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
Open
ignaciosantise
wants to merge
6
commits into
main
Choose a base branch
from
review-wpay-data-collection-docs
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
bdbef82
docs(wcp): add custom theming to data collection form + clarity cleanup
ignaciosantise e0fddb8
docs(wcp): unify wallet page structure and declutter navigation
ignaciosantise 3a14b0a
Merge remote-tracking branch 'origin/main' into review-wpay-data-coll…
ignaciosantise be3b963
docs(wcp): tidy WalletKit Flutter sections
ignaciosantise 1808f60
docs(wcp): rename standalone "Configuration" to "Initialization"
ignaciosantise 266d439
docs(wcp): strip padding from Dart base64url prefill encoding
ignaciosantise File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,7 @@ Add `walletconnect_pay` package to your `pubspec.yaml` or simply run: | |
| flutter pub add walletconnect_pay | ||
| ``` | ||
|
|
||
| ## Configuration | ||
| ## Initialization | ||
|
|
||
| Initialize the `WalletConnectPay` client with your WCP ID and client ID or API key: | ||
|
|
||
|
|
@@ -55,7 +55,7 @@ try { | |
| } | ||
| ``` | ||
|
|
||
| ### Configuration Parameters | ||
| **Configuration Parameters** | ||
|
|
||
| | Parameter | Type | Required | Description | | ||
| |-----------|------|----------|-------------| | ||
|
|
@@ -170,47 +170,54 @@ if (response.info != null) { | |
| print('Merchant: ${response.info!.merchant.name}'); | ||
| } | ||
|
|
||
| // Check if data collection is required | ||
| if (response.collectData != null) { | ||
| print('Data collection required: ${response.collectData!.fields.length} fields'); | ||
| // Check which options require data collection (per-option) | ||
| for (final option in response.options) { | ||
| if (option.collectData != null) { | ||
| print('Option ${option.id} requires info capture'); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| </Step> | ||
|
|
||
| <Step title="Collect User Data (If Required)" titleSize="h3"> | ||
|
|
||
| Some payments may require additional user data. After the user selects an option, check for `collectData` in the payment options response and run this step **before** fetching the required payment actions — the backend rejects the actions request with `400 IC data required` for options needing Information Capture if data has not yet been collected: | ||
| After the user selects an option, check for `collectData` on it. If present, collect the data **before** fetching the required actions. | ||
|
|
||
| <WebViewOverview /> | ||
|
|
||
| ```dart | ||
| if (response.collectData?.url != null) { | ||
| // Use the "required" list from response.collectData.schema to determine which fields to prefill | ||
| if (selectedOption.collectData?.url != null) { | ||
| // Use the "required" list from selectedOption.collectData.schema to determine which fields to prefill | ||
| final prefillData = { | ||
| 'fullName': 'John Doe', | ||
| 'dob': '1990-01-15', | ||
| 'pobAddress': '123 Main St, New York, NY 10001', | ||
| }; | ||
| final prefillJson = jsonEncode(prefillData); | ||
| final prefillBase64 = base64Url.encode(utf8.encode(prefillJson)); | ||
| final uri = Uri.parse(response.collectData!.url); | ||
| // Encode prefill as base64url | ||
| final prefillBase64 = base64Url.encode(utf8.encode(jsonEncode(prefillData))).replaceAll('=', ''); | ||
| final uri = Uri.parse(selectedOption.collectData!.url); | ||
| final webViewUrl = uri.replace( | ||
| queryParameters: {...uri.queryParameters, 'prefill': prefillBase64}, | ||
| queryParameters: { | ||
| ...uri.queryParameters, | ||
| 'prefill': prefillBase64, | ||
| // Optional appearance params (see "Form URL parameters"): | ||
| 'theme': 'dark', // "light" | "dark" | ||
| // themeVariables is a base64url string exported from the Pay Dashboard: | ||
| // 'themeVariables': themeVariables, | ||
| }, | ||
| ).toString(); | ||
|
|
||
| // Show WebView — see WebView Implementation section below | ||
| // Show WebView — see Data Collection Implementation section below | ||
| showDataCollectionWebView(webViewUrl); | ||
| } | ||
| ``` | ||
|
|
||
| <WebViewMessageTypes /> | ||
|
|
||
| The WebView submits the collected data directly to the backend, so you do **not** pass `collectedData` to `confirmPayment` later. | ||
|
|
||
| </Step> | ||
|
|
||
| <Step title="Get Required Payment Actions" titleSize="h3"> | ||
| <Step title="Get Required Actions" titleSize="h3"> | ||
|
|
||
| Get the required wallet actions (e.g., transactions to sign) for a selected payment option: | ||
|
|
||
|
|
@@ -234,10 +241,41 @@ for (final action in actions) { | |
| } | ||
| ``` | ||
|
|
||
| </Step> | ||
|
|
||
| <Step title="Sign Actions" titleSize="h3"> | ||
|
|
||
| Sign each action using your wallet's signing implementation, dispatching on the RPC method: | ||
|
|
||
| ```dart | ||
| // Sign each action based on its RPC method | ||
| final signatures = <String>[]; | ||
| for (final action in actions) { | ||
| final rpc = action.walletRpc; | ||
| switch (rpc.method) { | ||
| case 'eth_signTypedData_v4': | ||
| signatures.add(await signTypedData(rpc.chainId, rpc.params)); | ||
| break; | ||
| case 'eth_sendTransaction': | ||
| signatures.add(await sendTransaction(rpc.chainId, rpc.params)); | ||
| break; | ||
| case 'personal_sign': | ||
| signatures.add(await personalSign(rpc.chainId, rpc.params)); | ||
| break; | ||
| default: | ||
| throw UnimplementedError('Unsupported RPC method: ${rpc.method}'); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| <Note> | ||
| Payment options may include multiple actions with different RPC methods. For example, a Permit2 payment where the user lacks sufficient allowance returns two actions: an `eth_sendTransaction` to approve the token allowance, followed by an `eth_signTypedData_v4` to sign the Permit2 transfer. Your wallet must check `action.walletRpc.method` and dispatch to the appropriate handler. For full implementation guidance, see [USDT support](/payments/wallets/token-chain-support/usdt-support). | ||
| </Note> | ||
|
|
||
| <Warning> | ||
| Signatures must be in the same order as the actions array. | ||
| </Warning> | ||
|
|
||
| </Step> | ||
|
|
||
| <Step title="Confirm Payment" titleSize="h3"> | ||
|
|
@@ -272,16 +310,18 @@ When using the WebView data-collection approach, you do **not** pass `collectedD | |
|
|
||
| </Steps> | ||
|
|
||
| ## WebView Implementation | ||
| ## Data Collection Implementation | ||
|
|
||
| When `collectData.url` is present, display the URL in a WebView using the `webview_flutter` package (v4.10.0+). Add it to your `pubspec.yaml`: | ||
| When `selectedOption.collectData.url` is present, display the URL in a WebView using the `webview_flutter` package (v4.10.0+). Add it to your `pubspec.yaml`: | ||
|
|
||
| ```yaml | ||
| dependencies: | ||
| webview_flutter: ^4.10.0 | ||
| url_launcher: ^6.1.0 | ||
| ``` | ||
|
|
||
| <WebViewBestPractices /> | ||
|
|
||
| ```dart | ||
| import 'dart:convert'; | ||
| import 'package:flutter/material.dart'; | ||
|
|
@@ -367,14 +407,20 @@ class _PayDataCollectionWebViewState extends State<PayDataCollectionWebView> { | |
| } | ||
| } | ||
|
|
||
| String buildPrefillUrl(String baseUrl, Map<String, String> prefillData) { | ||
| if (prefillData.isEmpty) return baseUrl; | ||
| final json = jsonEncode(prefillData); | ||
| final base64 = base64Url.encode(utf8.encode(json)); | ||
| String buildFormUrl( | ||
| String baseUrl, { | ||
| Map<String, String> prefillData = const {}, | ||
| String? theme, // "light" or "dark" | ||
| String? themeVariables, // base64url string exported from the Pay Dashboard | ||
| }) { | ||
| final uri = Uri.parse(baseUrl); | ||
| return uri.replace( | ||
| queryParameters: {...uri.queryParameters, 'prefill': base64}, | ||
| ).toString(); | ||
| final params = {...uri.queryParameters}; | ||
| if (prefillData.isNotEmpty) { | ||
| params['prefill'] = base64Url.encode(utf8.encode(jsonEncode(prefillData))).replaceAll('=', ''); | ||
| } | ||
| if (theme != null) params['theme'] = theme; | ||
| if (themeVariables != null) params['themeVariables'] = themeVariables; | ||
| return uri.replace(queryParameters: params).toString(); | ||
| } | ||
| ``` | ||
|
|
||
|
|
@@ -421,9 +467,9 @@ class PaymentService { | |
| // for options needing Information Capture if data wasn't collected first. | ||
| // The WebView submits the data directly to the backend, so it is NOT | ||
| // passed to confirmPayment later. | ||
| if (optionsResponse.collectData?.url != null) { | ||
| if (selectedOption.collectData?.url != null) { | ||
| // Show WebView and wait for IC_COMPLETE | ||
| await showDataCollectionWebView(optionsResponse.collectData!.url); | ||
| await showDataCollectionWebView(selectedOption.collectData!.url); | ||
| } | ||
|
|
||
| // Step 4: Get required payment actions | ||
|
|
@@ -485,11 +531,11 @@ class PaymentService { | |
|
|
||
| ## API Reference | ||
|
|
||
| ### WalletConnectPay | ||
| **WalletConnectPay** | ||
|
|
||
| The main class for interacting with the WalletConnect Pay SDK. | ||
|
|
||
| #### Constructor | ||
| **Constructor** | ||
|
|
||
| ```dart | ||
| WalletConnectPay({ | ||
|
|
@@ -500,7 +546,7 @@ WalletConnectPay({ | |
| }) | ||
| ``` | ||
|
|
||
| #### Methods | ||
| **Methods** | ||
|
|
||
| | Method | Description | | ||
| |--------|-------------| | ||
|
|
@@ -509,9 +555,9 @@ WalletConnectPay({ | |
| | `Future<List<Action>> getRequiredPaymentActions({required GetRequiredPaymentActionsRequest request})` | Gets the required wallet actions for a selected option (to be called if the selected option does not have actions included) | | ||
| | `Future<ConfirmPaymentResponse> confirmPayment({required ConfirmPaymentRequest request})` | Confirms a payment | | ||
|
|
||
| ## Models | ||
| ## Data Models | ||
|
|
||
| ### GetPaymentOptionsRequest | ||
| **GetPaymentOptionsRequest** | ||
|
|
||
| ```dart | ||
| GetPaymentOptionsRequest({ | ||
|
|
@@ -521,7 +567,7 @@ GetPaymentOptionsRequest({ | |
| }) | ||
| ``` | ||
|
|
||
| ### PaymentOptionsResponse | ||
| **PaymentOptionsResponse** | ||
|
|
||
| ```dart | ||
| PaymentOptionsResponse({ | ||
|
|
@@ -533,7 +579,7 @@ PaymentOptionsResponse({ | |
| }) | ||
| ``` | ||
|
|
||
| ### PaymentResultInfo | ||
| **PaymentResultInfo** | ||
|
|
||
| ```dart | ||
| class PaymentResultInfo { | ||
|
|
@@ -542,7 +588,7 @@ class PaymentResultInfo { | |
| } | ||
| ``` | ||
|
|
||
| ### PaymentInfo | ||
| **PaymentInfo** | ||
|
|
||
| ```dart | ||
| PaymentInfo({ | ||
|
|
@@ -554,7 +600,7 @@ PaymentInfo({ | |
| }) | ||
| ``` | ||
|
|
||
| ### PaymentOption | ||
| **PaymentOption** | ||
|
|
||
| ```dart | ||
| PaymentOption({ | ||
|
|
@@ -563,10 +609,11 @@ PaymentOption({ | |
| required PayAmount amount, | ||
| @JsonKey(name: 'etaS') required int etaSeconds, | ||
| required List<Action> actions, | ||
| CollectDataAction? collectData, // Per-option data collection (null if not required) | ||
| }) | ||
| ``` | ||
|
|
||
| ### ConfirmPaymentRequest | ||
| **ConfirmPaymentRequest** | ||
|
|
||
| ```dart | ||
| ConfirmPaymentRequest({ | ||
|
|
@@ -578,7 +625,7 @@ ConfirmPaymentRequest({ | |
| }) | ||
| ``` | ||
|
|
||
| ### ConfirmPaymentResponse | ||
| **ConfirmPaymentResponse** | ||
|
|
||
| ```dart | ||
| ConfirmPaymentResponse({ | ||
|
|
@@ -588,7 +635,7 @@ ConfirmPaymentResponse({ | |
| }) | ||
| ``` | ||
|
|
||
| ### PaymentStatus | ||
| **PaymentStatus** | ||
|
|
||
| ```dart | ||
| enum PaymentStatus { | ||
|
|
@@ -600,7 +647,7 @@ enum PaymentStatus { | |
| } | ||
| ``` | ||
|
|
||
| ### Action & WalletRpcAction | ||
| **Action & WalletRpcAction** | ||
|
|
||
| ```dart | ||
| class Action { | ||
|
|
@@ -614,7 +661,7 @@ class WalletRpcAction { | |
| } | ||
| ``` | ||
|
|
||
| ### CollectDataAction | ||
| **CollectDataAction** | ||
|
|
||
| ```dart | ||
| class CollectDataAction { | ||
|
|
@@ -651,7 +698,7 @@ All errors include: | |
| - `details`: Additional error details | ||
| - `stacktrace`: Stack trace | ||
|
|
||
| ### Example Error Handling | ||
| **Example Error Handling** | ||
|
|
||
| ```dart | ||
| try { | ||
|
|
@@ -691,8 +738,5 @@ try { | |
|
|
||
| 8. **User Data**: Only collect data when `collectData` is present in the response and you don't already have the required user data. If you already have the required data, you can submit this without collecting from the user. You must make sure the user accepts WalletConnect Terms and Conditions and Privacy Policy before submitting user information to WalletConnect. | ||
|
|
||
| 9. **WebView Data Collection**: When `collectData.url` is present, display the URL in a WebView using `webview_flutter` rather than building native forms. The WebView handles form rendering, validation, and T&C acceptance. | ||
|
|
||
| ## Examples | ||
| 9. **WebView Data Collection**: When `selectedOption.collectData.url` is present, display the URL in a WebView using `webview_flutter` rather than building native forms. The WebView handles form rendering, validation, and T&C acceptance. | ||
|
|
||
| For a complete example implementation, see the [reown_walletkit example](https://github.com/reown-com/reown_flutter/tree/master/packages/reown_walletkit/example/lib/walletconnect_pay). | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (this was redundant with the wallet sample link at top) |
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
the backend error info was moved to a shared snippet, still present in the docs