Skip to content

Commit 4e9972e

Browse files
authored
chore: Add documentation for deep links (MetaMask#22167)
Adding documentation about how to hook into the deep / universal links functionality <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a new, detailed deeplink handling guide with visual flowcharts and removes the legacy deeplinks doc. > > - **Docs**: > - **New Guides**: > - `docs/readme/deeplinking.md`: Comprehensive MetaMask Mobile deeplink guide covering link types, processing pipeline, action routing, signed link verification with `sig_params`, handler integration steps, testing, and security. > - `docs/readme/deeplinking-graphs.md`: Visual Mermaid flowcharts for full processing flow, signature creation/verification, dynamic parameters, and common scenarios. > - **Removed**: > - `docs/readme/deeplinks.md` (legacy, brief guide). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8b6a530. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent e5a4933 commit 4e9972e

3 files changed

Lines changed: 1007 additions & 85 deletions

File tree

docs/readme/deeplinking-graphs.md

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
# Deeplink Processing Visual Flowcharts
2+
3+
> 📚 **[Back to Main Deeplink Guide](./deeplinking.md)** for detailed explanations, implementation steps, and code examples
4+
5+
## Quick Navigation
6+
7+
- [Complete Deeplink Flow](#complete-deeplink-flow-with-signature-verification) - Main processing pipeline
8+
- [Signature Creation & Verification](#signature-creation-and-verification-detail) - How signing works
9+
- [Dynamic Parameters](#dynamic-parameters-example) - Adding unsigned params
10+
- [Common Scenarios](#common-scenarios) - Real-world examples
11+
12+
---
13+
14+
## Complete Deeplink Flow with Signature Verification
15+
16+
**Related Documentation:** [How Link Processing Works](./deeplinking.md#how-link-processing-works)
17+
18+
```mermaid
19+
flowchart TD
20+
Start[User Clicks Deeplink<br/>https://link.metamask.io/perps?...] --> Parse[DeeplinkManager.parse<br/>Extract URL components and params]
21+
22+
Parse --> Protocol{Protocol?}
23+
Protocol -->|HTTPS| Universal[handleUniversalLink]
24+
Protocol -->|Other| Other[Other Protocols<br/>metamask://, wc://]
25+
26+
Universal --> Domain{Domain Valid?<br/>link.metamask.io or<br/>link-test.metamask.io?}
27+
Domain -->|No| InvalidDomain[INVALID DOMAIN<br/>Show error modal]
28+
Domain -->|Yes| CheckSig{Has Signature?<br/>url.searchParams.has'sig'}
29+
30+
CheckSig -->|Yes| VerifySig[Verify Signature]
31+
CheckSig -->|No| PublicLink1[PUBLIC LINK]
32+
33+
VerifySig --> BuildCanonical[Build Canonical URL<br/>• Get params from sig_params list<br/>• Include sig_params itself<br/>• Sort alphabetically]
34+
BuildCanonical --> CryptoVerify[Verify with Public Key<br/>ECDSA P-256]
35+
36+
CryptoVerify -->|VALID| PrivateLink[PRIVATE LINK<br/>Trusted source]
37+
CryptoVerify -->|INVALID| InvalidLink[INVALID LINK<br/>Tampered/Wrong signature]
38+
CryptoVerify -->|MISSING| PublicLink2[PUBLIC LINK<br/>No signature]
39+
40+
PrivateLink --> Modal
41+
PublicLink1 --> Modal
42+
PublicLink2 --> Modal
43+
InvalidLink --> Modal
44+
InvalidDomain --> Modal
45+
46+
Modal[Interstitial Modal Decision] --> ModalType{Link Type?}
47+
ModalType -->|Private| ShowPrivate[Show confirmation<br/>can remember choice]
48+
ModalType -->|Public| ShowPublic[Show security warning]
49+
ModalType -->|Invalid| ShowInvalid[Show 'Page doesn't exist' modal]
50+
ModalType -->|Unsupported| ShowUnsupported[Show 'Not supported' modal]
51+
ModalType -->|Whitelisted| Skip[Skip modal<br/>WC, enable-card-button]
52+
53+
ShowPrivate --> UserContinue{User Continues?}
54+
ShowPublic --> UserContinue
55+
ShowInvalid --> UserContinue
56+
ShowUnsupported --> UserContinue
57+
Skip --> Route
58+
59+
UserContinue -->|Yes| Route[Action Routing]
60+
UserContinue -->|No| End[End]
61+
62+
Route --> Action{Action Type?}
63+
Action -->|swap| HandleSwap[_handleSwap]
64+
Action -->|buy| HandleBuy[_handleBuyCrypto]
65+
Action -->|perps| HandlePerps[_handlePerps]
66+
Action -->|send| HandleSend[_handleEthereumUrl]
67+
Action -->|dapp| HandleDapp[_handleBrowserUrl]
68+
Action -->|rewards| HandleRewards[_handleRewards]
69+
Action -->|other| HandleOther[Other Handlers...]
70+
71+
HandleSwap --> Execute
72+
HandleBuy --> Execute
73+
HandlePerps --> Execute
74+
HandleSend --> Execute
75+
HandleDapp --> Execute
76+
HandleRewards --> Execute
77+
HandleOther --> Execute
78+
79+
Execute[Handler Execution<br/>1. Parse parameters<br/>2. Navigate to screen<br/>3. Pass data to components<br/>4. Update app state]
80+
81+
style Start fill:#e1f5ff
82+
style PrivateLink fill:#d4edda
83+
style PublicLink1 fill:#fff3cd
84+
style PublicLink2 fill:#fff3cd
85+
style InvalidLink fill:#f8d7da
86+
style InvalidDomain fill:#f8d7da
87+
style Execute fill:#d4edda
88+
```
89+
90+
## Signature Creation and Verification Detail
91+
92+
**Related Documentation:** [Signature Verification](./deeplinking.md#signature-verification)
93+
94+
### Server-Side (link-signer-api)
95+
96+
```mermaid
97+
flowchart TD
98+
Input[INPUT:<br/>https://link.metamask.io/perps?screen=asset&symbol=BTC]
99+
100+
Input --> Extract[Extract All Parameters<br/>params = screen, symbol]
101+
Extract --> CreateSigParams[Create sig_params<br/>sig_params = 'screen,symbol']
102+
CreateSigParams --> AddToURL[Add sig_params to URL<br/>Sort all parameters]
103+
AddToURL --> Sign[Sign Complete URL<br/>ECDSA P-256 with Private Key]
104+
Sign --> Append[Append Signature<br/>sig = base64url signature]
105+
Append --> Output[OUTPUT:<br/>https://link.metamask.io/perps?screen=asset&<br/>sig_params=screen,symbol&symbol=BTC&sig=MEUCIQDx...]
106+
107+
style Input fill:#e1f5ff
108+
style Output fill:#d4edda
109+
```
110+
111+
### Client-Side (MetaMask Mobile)
112+
113+
```mermaid
114+
flowchart TD
115+
Input[INPUT:<br/>https://link.metamask.io/perps?screen=asset&<br/>sig_params=screen,symbol&symbol=BTC&sig=MEUCIQDx...]
116+
117+
Input --> ExtractParams[Extract sig_params<br/>'screen,symbol' → screen, symbol]
118+
ExtractParams --> BuildCanonical[Build Canonical URL<br/>Include ONLY:<br/>• params in sig_params list<br/>• sig_params itself<br/>• Sort alphabetically]
119+
BuildCanonical --> Canonical[Canonical URL:<br/>?screen=asset&sig_params=screen,symbol&symbol=BTC]
120+
Canonical --> Verify[Verify Signature<br/>ECDSA P-256 with Public Key]
121+
122+
Verify -->|✅| Valid[VALID<br/>Signature matches]
123+
Verify -->|❌| Invalid[INVALID<br/>Signature doesn't match]
124+
125+
style Input fill:#e1f5ff
126+
style Valid fill:#d4edda
127+
style Invalid fill:#f8d7da
128+
```
129+
130+
## Dynamic Parameters Example
131+
132+
**Related Documentation:** [Benefits of Dynamic Signing (sig_params)](./deeplinking.md#benefits-of-dynamic-signing-sig_params)
133+
134+
```mermaid
135+
flowchart TD
136+
Server[SIGNED URL FROM SERVER<br/>https://link.metamask.io/swap?<br/>chainId=1&sig_params=chainId&sig=X]
137+
138+
Server --> Client[CLIENT ADDS UNSIGNED PARAMS<br/>debug=true, userId=123]
139+
140+
Client --> Final[FINAL URL TO VERIFY<br/>https://link.metamask.io/swap?chainId=1&<br/>debug=true&userId=123&<br/>sig_params=chainId&sig=X]
141+
142+
Final --> Canonicalize[CANONICALIZATION FOR VERIFY<br/><br/>sig_params says: 'chainId'<br/>canonical URL = ?chainId=1&sig_params=chainId<br/><br/>debug and userId are IGNORED<br/>not in sig_params]
143+
144+
Canonicalize --> Valid[✅ SIGNATURE VALID!<br/>Because canonical URL<br/>matches what was signed]
145+
146+
style Server fill:#e1f5ff
147+
style Client fill:#fff3cd
148+
style Final fill:#e1f5ff
149+
style Canonicalize fill:#f0f0f0
150+
style Valid fill:#d4edda
151+
```
152+
153+
## Common Scenarios
154+
155+
**Related Documentation:** [Link Types](./deeplinking.md#link-types) | [Testing Links](./deeplinking.md#testing-links)
156+
157+
### Scenario 1: Marketing Campaign (Public Link)
158+
159+
```mermaid
160+
flowchart LR
161+
Click[User clicks<br/>https://link.metamask.io/buy] --> NoSig[No signature]
162+
NoSig --> Warning[Shows warning interstitial]
163+
Warning --> Proceed{User proceeds?}
164+
Proceed -->|Yes| Buy[Opens buy screen]
165+
Proceed -->|No| Cancel[Cancelled]
166+
167+
style Click fill:#e1f5ff
168+
style Warning fill:#fff3cd
169+
style Buy fill:#d4edda
170+
```
171+
172+
### Scenario 2: Internal Testing (Private Link)
173+
174+
```mermaid
175+
flowchart LR
176+
Click[User clicks<br/>https://link.metamask.io/perps?<br/>sig=XXX&sig_params=...] --> HasSig[Has valid signature]
177+
HasSig --> Confirm[Shows confirmation<br/>or skips if remembered]
178+
Confirm --> Proceed{User proceeds?}
179+
Proceed -->|Yes| Perps[Opens perps with<br/>trusted params]
180+
Proceed -->|No| Cancel[Cancelled]
181+
182+
style Click fill:#e1f5ff
183+
style HasSig fill:#d4edda
184+
style Perps fill:#d4edda
185+
```
186+
187+
### Scenario 3: Tampered Link (Invalid)
188+
189+
```mermaid
190+
flowchart LR
191+
Click[User clicks<br/>https://link.metamask.io/swap?<br/>amount=1000&sig=XXX] --> Check[Signature doesn't match<br/>amount was changed]
192+
Check --> Modal[Shows 'This page<br/>doesn't exist' modal]
193+
Modal --> Options[Options:<br/>• Update app<br/>• Go to home page]
194+
Options --> Rejected[Link rejected]
195+
196+
style Click fill:#e1f5ff
197+
style Check fill:#f8d7da
198+
style Modal fill:#f8d7da
199+
style Rejected fill:#f8d7da
200+
```
201+
202+
### Scenario 4: WalletConnect (Whitelisted)
203+
204+
```mermaid
205+
flowchart LR
206+
Click[User clicks<br/>https://link.metamask.io/wc?<br/>uri=wc:123...] --> Whitelist[WC action is whitelisted]
207+
Whitelist --> Skip[Skips interstitial<br/>completely]
208+
Skip --> WC[Direct to WalletConnect<br/>handler]
209+
210+
style Click fill:#e1f5ff
211+
style Whitelist fill:#d4edda
212+
style WC fill:#d4edda
213+
```

0 commit comments

Comments
 (0)