|
| 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