|
| 1 | +--- |
| 2 | +CIP: 99 |
| 3 | +Title: Proof of Onboarding |
| 4 | +Status: Active |
| 5 | +Category: Wallets |
| 6 | +Authors: |
| 7 | +- Adam Dean <adam@crypto2099.io> |
| 8 | +- Carl <vegas@hosky.io> |
| 9 | +- Alex Dochioiu <alex@dochioiu.com> |
| 10 | +Implementors: |
| 11 | +- VESPR Wallet <https://www.vespr.xyz/> |
| 12 | +- Yoroi Wallet <https://yoroi-wallet.com/> |
| 13 | +Discussions: |
| 14 | +- https://github.com/cardano-foundation/CIPs/pull/546 |
| 15 | +Created: 2023-06-20 |
| 16 | +License: CC-BY-4.0 |
| 17 | +--- |
| 18 | + |
| 19 | +## Abstract |
| 20 | + |
| 21 | +Since at least 2021 when Cardano entered the Mary Era and implemented Native Assets, projects and creators building on |
| 22 | +the network have sought a means to distribute their tokens efficiently to users. Of particular frustration has been the |
| 23 | +ability to onboard new users at real-world events. Solutions for this historically have been to create and preload |
| 24 | +"paper wallets" where a seed phrase and accompanying password is generated by the project, pre-populated with tokens and |
| 25 | +ADA, and then delivered over to attendees of said event. |
| 26 | + |
| 27 | +The creation of this addendum to the [CIP-13 Cardano URI scheme](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0013/README.md) seeks to minimize this friction and take advantage of |
| 28 | +existing technology to enable a new era of user onboarding, particularly at real world events through the use of a |
| 29 | +defined URI scheme enabling instant and frictionless communication between a project's "token fountain" and the user's |
| 30 | +wallet to reward, incentivize, and onboard new users easier than ever. |
| 31 | + |
| 32 | +This CIP defines an extension to the CIP-13 URI Scheme as well as an API specification to facilitate and streamline |
| 33 | +communications between wallets and project servers. |
| 34 | + |
| 35 | +## Motivation: Why is this CIP necessary? |
| 36 | + |
| 37 | +By leveraging the power of Cardano-specific URIs (CIP-13) and the modern technological advances of mobile devices and |
| 38 | +wallets we can provide a framework for Cardano projects to attend real world events, incentivize or reward attendees via |
| 39 | +their Native Assets, and have facts and figures to help support and analyze the impact that their attendance had (Proof |
| 40 | +of Onboarding). |
| 41 | + |
| 42 | +## Specification |
| 43 | + |
| 44 | +### CIP-13 Cardano URI Extensions |
| 45 | + |
| 46 | +Distributing Native Assets (and/or ADA) to attendees of IRL events has historically been a pain point in the ecosystem. |
| 47 | +Some implemented solutions have included: Pre-generating wallet seed phrases and pre-populating these wallets with a |
| 48 | +minimum amount of ADA as well as the desired Native Assets, (re)creating token fountain/faucet designs which can be |
| 49 | +cumbersome and not user-friendly to instruct individuals to install a wallet, visit a website, enter a code and claim |
| 50 | +tokens. |
| 51 | + |
| 52 | +The Cardano Token Claim URI schema is proposed to allow wallets (particularly mobile wallets) to implement a QR-friendly |
| 53 | +URI structure allowing for easy onboarding and distribution of Native Assets and/or ADA to individuals in a variety of |
| 54 | +situations but not least of which being at IRL events specifically tailored and geared to onboarding new users to the |
| 55 | +ecosystem. |
| 56 | + |
| 57 | +Examples: |
| 58 | +```html |
| 59 | +<!-- Token Claim URIs --> |
| 60 | +<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=consensus2023">Claim $HOSKY</a> |
| 61 | +<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io%2Fconsensus23&code=ABC123">Claim $HOSKY</a> |
| 62 | +<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=ABC123&invoice=123456">Claim NFTxLV Commermorative NFT!</a> |
| 63 | +``` |
| 64 | + |
| 65 | +#### ABNF Grammar |
| 66 | + |
| 67 | +* For a token claim URI (authority = `claim`), a versioning path, a `faucet_url` and a required `code`. |
| 68 | +* Additional query parameters may be provided and should be passed through to the provided `faucet_url` without modification. |
| 69 | + |
| 70 | +``` |
| 71 | +cardanourn = "web+cardano:" claimtokenref |
| 72 | +
|
| 73 | +claimtokenref = "//claim" claimversion claimquery |
| 74 | +claimversion = "/v1" |
| 75 | +claimquery = ( "?" claimurl) ( "&" claimcode) |
| 76 | +claimurl = "faucet_url=" text |
| 77 | +claimcode = "code=" text |
| 78 | +``` |
| 79 | + |
| 80 | +#### Token Claim URI Queries |
| 81 | + |
| 82 | +**All arguments for Token Claim URIs should be URL-encoded** |
| 83 | + |
| 84 | +***Version 1 URIs*** |
| 85 | + |
| 86 | +Version 1 URIs must include a `faucet_url` and a `code` as required parameters. |
| 87 | + |
| 88 | +URIs may include additional arguments to suit the needs of the project's faucet API. |
| 89 | + |
| 90 | +#### Handling Token Claim URI Queries |
| 91 | + |
| 92 | +The token claim URI should consist of a required versioning `path` (i.e. `/v1`) as well as one or more required |
| 93 | +or optional URL-encoded arguments. |
| 94 | + |
| 95 | +All Token Claim URIs must include a URL-encoded `faucet_url` argument as well as a `code` argument. |
| 96 | + |
| 97 | +The wallet provider should send a POST request to the provided `Faucet URL` that includes: |
| 98 | +* The change/receipt wallet address of the user |
| 99 | +* Any additional arguments specified in the URI as key: value pairs |
| 100 | + |
| 101 | +**Example:** |
| 102 | + |
| 103 | +``` |
| 104 | +URI: web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io%2Fconsensus23&code=ABC123 |
| 105 | +Version: 1 |
| 106 | +URL: https://claim.hosky.io/consensus23 |
| 107 | +CODE: ABC123 |
| 108 | +JSON POST Data: |
| 109 | +``` |
| 110 | +```json |
| 111 | +{ |
| 112 | + "address": "addr1abc...xyz", |
| 113 | + "code": "ABC123" |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +##### Note on the `address` field |
| 118 | + |
| 119 | +The wallet should always send the recipient address in bech32 format. If a particular token faucet implementation wishes |
| 120 | +to restrict or limit access to their faucet based on staking key or individual wallet address, this should be handled at |
| 121 | +the server end. |
| 122 | + |
| 123 | +**Supported Addresses** |
| 124 | + |
| 125 | +* Shelley-era `enterprise` address consisting of only a payment key |
| 126 | +* Shelley-era `staking` address consisting of a payment and staking key |
| 127 | + |
| 128 | +##### Note on the `code` field |
| 129 | + |
| 130 | +The code is required. Specifying a `code` allows for reliable tracking and/or limiting of claims to the faucet host. |
| 131 | +Codes can be used to identify attendees of particular events (i.e. CODE = `consensus2023`) or can be a unique, one-time |
| 132 | +code per user (i.e. CODE = `abc123xyz987`). In this way we leave the code to be flexible to match a variety of |
| 133 | +analytical use cases depending upon the needs of the implementing project. |
| 134 | + |
| 135 | +#### Security Considerations |
| 136 | + |
| 137 | +1. Wallets should prompt/warn users prior to sending potentially sensitive information (wallet address + code) via the |
| 138 | + token claim URI. An informational pop-up or confirmation modal should be displayed to users such as: |
| 139 | + `We are about to send your address and code 123456 to https://claim.hosky.io. Are you sure you want to proceed?` |
| 140 | + |
| 141 | +### Process Flow |
| 142 | + |
| 143 | +The envisioned process flow for the POO Protocol is as follows: |
| 144 | +1. The project set asides some amount of budget (tokens + Lovelace [minUTxO]) for a given marketing push or IRL event |
| 145 | +2. If desired, one or more `codes` are generated to help track and analyze claiming figures |
| 146 | +3. QR Code(s) may be generated, printed, and otherwise displayed or given to users during the course of events |
| 147 | +4. Users scan the code with their mobile light wallet |
| 148 | +5. The light wallet makes a POST request to the API endpoint specified in the Cardano URI containing the user's wallet address and the included code (if present) |
| 149 | +6. The project API returns a documented status code indicating the success or failure of the operation |
| 150 | +7. If a successful status is detected and returned, the project issues tokens to the specified address per their campaign settings |
| 151 | + |
| 152 | +### URI Format |
| 153 | + |
| 154 | +The URI format consists of the CIP-13 `web+cardano://` scheme, followed by the `claim` authority, then a `version` path. |
| 155 | + |
| 156 | +***NOTE: ALL ARGUMENTS SHOULD BE URL-ENCODED*** |
| 157 | + |
| 158 | +#### Version 1 |
| 159 | + |
| 160 | +Version 1 URIs must include `/v1` as the path of the URI. |
| 161 | + |
| 162 | +Version 1 URIs must include two required arguments: |
| 163 | + |
| 164 | +* `faucet_url` as a fully-typed URL (i.e. https://claim.hosky.io) |
| 165 | +* `code` as either a campaign identifier or unique, one-time use code |
| 166 | + |
| 167 | +Version 1 URIs may include additional query parameters that should be passed through to the api server. |
| 168 | + |
| 169 | +_Version 1 Examples:_ |
| 170 | + |
| 171 | +```html |
| 172 | +<!-- A Cardano Claim URI with campaign identifier code --> |
| 173 | +<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=consensus2023">Thanks for attending Consensus 2023!</a> |
| 174 | + |
| 175 | +<!-- A Cardano Claim URI with unique, one-time use code --> |
| 176 | +<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=dff6508d8dfb4e128fd67e9ff54af147">Claim your $HOSKY now!</a> |
| 177 | + |
| 178 | +<!-- A Cardano Claim URI with a campaign-specific code and optional user_id argument --> |
| 179 | +<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=NFTxLV2023&user_id=Idjiot1337">Get your $HOSKY!</a> |
| 180 | +``` |
| 181 | + |
| 182 | +### Wallet Requests |
| 183 | + |
| 184 | +Light wallets that detect and support `web+cardano` URIs as well as mobile wallets who detect either a QR code or other |
| 185 | +link with this format should parse the URI and send a `POST` request to the specified URL containing a JSON payload |
| 186 | +including: |
| 187 | + |
| 188 | +* The user's wallet receive address |
| 189 | +* The code |
| 190 | +* Additional URI query parameters passed through |
| 191 | + |
| 192 | +#### Examples |
| 193 | + |
| 194 | +##### _Faucet URL + Campaign Code_ |
| 195 | +- URI: ```web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=NFTxLV2023``` |
| 196 | +- Faucet URL: ```https://claim.nftxlv.com``` |
| 197 | +- POST JSON Data: |
| 198 | +```json |
| 199 | +{ |
| 200 | + "address": "addr1abc...xyz", |
| 201 | + "code": "NFTxLV2023" |
| 202 | +} |
| 203 | +``` |
| 204 | + |
| 205 | +##### _Faucet URL + Unique Code_ |
| 206 | +- URI: ```web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=NFTxLV2023``` |
| 207 | +- Faucet URL: ```https://claim.hosky.io``` |
| 208 | +- POST JSON Data: |
| 209 | +```json |
| 210 | +{ |
| 211 | + "address": "addr1abc...xyz", |
| 212 | + "code": "ABC123" |
| 213 | +} |
| 214 | +``` |
| 215 | + |
| 216 | +##### _Faucet URL + Campaign Code + Custom User ID_ |
| 217 | +- URI: ```web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=NFTxLV2023&user_id=Adam1337``` |
| 218 | +- Faucet URL: ```https://claim.nftxlv.com``` |
| 219 | +- POST JSON Data: |
| 220 | +```json |
| 221 | +{ |
| 222 | + "address": "addr1abc...xyz", |
| 223 | + "code": "NFTxLV2023", |
| 224 | + "user_id": "Adam1337" |
| 225 | +} |
| 226 | +``` |
| 227 | + |
| 228 | +### API Server Response Codes |
| 229 | + |
| 230 | +The API server is expected to return one of the following defined status blocks in `application/json` format. Any other |
| 231 | +responses from the API server should be considered invalid and discarded or display an error. |
| 232 | + |
| 233 | +The expected API that any token fountain implementation should follow and wallet integrators should expect is documented |
| 234 | +on Swagger! |
| 235 | + |
| 236 | +* [Version 1](https://app.swaggerhub.com/apis/CatastrophicCardano/FaucetAPI/1) |
| 237 | + |
| 238 | +#### Successful Responses |
| 239 | + |
| 240 | +##### Valid (200) |
| 241 | + |
| 242 | +First Successful Request |
| 243 | + |
| 244 | +```json |
| 245 | +{ |
| 246 | + "code": 200, |
| 247 | + "lovelaces": "2000000", |
| 248 | + "queue_position": 23, |
| 249 | + "status": "accepted", |
| 250 | + "tokens": { |
| 251 | + "a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235.484f534b59": "29433292000000" |
| 252 | + } |
| 253 | +} |
| 254 | +``` |
| 255 | + |
| 256 | +##### Valid Queued (201) |
| 257 | + |
| 258 | +Subsequent Successful Request (Address + Code Match) prior to token distribution |
| 259 | + |
| 260 | +```json |
| 261 | +{ |
| 262 | + "code": 201, |
| 263 | + "lovelaces": "2000000", |
| 264 | + "queue_position": 1, |
| 265 | + "status": "queued", |
| 266 | + "tokens": { |
| 267 | + "a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235.484f534b59": "29433292000000" |
| 268 | + } |
| 269 | +} |
| 270 | +``` |
| 271 | + |
| 272 | +##### Valid Complete (202) |
| 273 | + |
| 274 | +Subsequent Successful Request (Address + Code Match) after token(s) are distributed |
| 275 | + |
| 276 | +```json |
| 277 | +{ |
| 278 | + "code": 202, |
| 279 | + "lovelaces": "2000000", |
| 280 | + "status": "claimed", |
| 281 | + "tokens": { |
| 282 | + "a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235.484f534b59": "29433292000000" |
| 283 | + }, |
| 284 | + "tx_hash": "TX1234" |
| 285 | +} |
| 286 | +``` |
| 287 | + |
| 288 | +#### Error Responses |
| 289 | + |
| 290 | +##### Bad Request - Invalid Address (400) |
| 291 | + |
| 292 | +The provided address is not a valid Cardano address |
| 293 | + |
| 294 | +```json |
| 295 | +{ |
| 296 | + "code": 400, |
| 297 | + "status": "invalidaddress" |
| 298 | +} |
| 299 | +``` |
| 300 | + |
| 301 | +##### Bad Request - Missing Code (400) |
| 302 | + |
| 303 | +No code was provided in the request |
| 304 | + |
| 305 | +```json |
| 306 | +{ |
| 307 | + "code": 400, |
| 308 | + "status": "missingcode" |
| 309 | +} |
| 310 | +``` |
| 311 | + |
| 312 | +##### Bad Request - Invalid Network (400) |
| 313 | + |
| 314 | +The wallet provided is from the wrong network (testnet/mainnet) |
| 315 | + |
| 316 | +```json |
| 317 | +{ |
| 318 | + "code": 400, |
| 319 | + "status": "invalidnetwork" |
| 320 | +} |
| 321 | +``` |
| 322 | + |
| 323 | +##### Invalid - Not Known (404) |
| 324 | + |
| 325 | +The specified code does not exist |
| 326 | + |
| 327 | +```json |
| 328 | +{ |
| 329 | + "code": 404, |
| 330 | + "status": "notfound" |
| 331 | +} |
| 332 | +``` |
| 333 | + |
| 334 | +##### Invalid - Already Claimed (409) |
| 335 | + |
| 336 | +An address was already used (if not code present) or the code presented was found but the address did not match |
| 337 | + |
| 338 | +```json |
| 339 | +{ |
| 340 | + "code": 409, |
| 341 | + "status": "alreadyclaimed" |
| 342 | +} |
| 343 | +``` |
| 344 | + |
| 345 | +##### Invalid - Expired (410) |
| 346 | + |
| 347 | +For time-limited fountains, a code of 410 means that the period for redemption has expired |
| 348 | + |
| 349 | +```json |
| 350 | +{ |
| 351 | + "code": 410, |
| 352 | + "status": "expired" |
| 353 | +} |
| 354 | +``` |
| 355 | + |
| 356 | +##### Invalid - Too Early (425) |
| 357 | + |
| 358 | +For time-limited fountains, a code of 425 means that the period for redemption has not begun yet |
| 359 | + |
| 360 | +```json |
| 361 | +{ |
| 362 | + "code": 425, |
| 363 | + "status": "tooearly" |
| 364 | +} |
| 365 | +``` |
| 366 | + |
| 367 | +##### Invalid - Rate Limited (429) |
| 368 | + |
| 369 | +Rate limiting settings and details are left to the discretion and implementation of individual projects. A status code |
| 370 | +of 429 or this status response should be considered as a rate limiting response. |
| 371 | + |
| 372 | +```json |
| 373 | +{ |
| 374 | + "code": 429, |
| 375 | + "status": "ratelimited" |
| 376 | +} |
| 377 | +``` |
| 378 | + |
| 379 | +##### Server Error (500) |
| 380 | + |
| 381 | +Implementations should of course be prepared to handle situations where a server is non-responsive for any reason and |
| 382 | +be prepared to handle any other, non-specified error codes including 500 codes. |
| 383 | + |
| 384 | +### Versioning & Modification Rules |
| 385 | + |
| 386 | +If there is sufficient justification in the future for modification of this standard to the point that a "Version 2" |
| 387 | +would be necessary, those changes MUST be submitted as a new, separate CIP to this repository and follow all applicable |
| 388 | +CIP standards for acceptance. Examples of "major" changes that might justify a new version of this CIP include: |
| 389 | +fundamentally altering the URI structure, adding or removing a **required** field, or any other non-backwards compatible |
| 390 | +changes to the [Process Flow](#process-flow). |
| 391 | + |
| 392 | +Minor changes for grammar, clarity, or functionality that fall within the scope of "Version 1" of this document may be |
| 393 | +made by editing this document directly. Such changes include: grammatical or exposition changes to improve readability |
| 394 | +or clarity of communication, improvements to documented code examples, additional or optional server response information, |
| 395 | +etc. |
| 396 | + |
| 397 | +## Rationale: How does this CIP achieve its goals? |
| 398 | + |
| 399 | +By creating a well-defined standard for both a CIP-13 URI scheme and the expected API response(s) we can create a |
| 400 | +framework that both wallets and projects can utilize to encourage and onboard new users into the ecosystem via Native |
| 401 | +Asset incentive models without needlessly and constantly reinventing the wheel for each product or project. |
| 402 | + |
| 403 | +Furthermore, the aforementioned "paper wallet" technique has many drawbacks including: |
| 404 | +* The person(s) responsible for generating the paper wallets at some point have access to the seed phrases generated, leading to a potential security vulnerability |
| 405 | +* Projects would need to preload these wallets with funds/tokens; this makes it difficult and/or impossible to reliably know how many of the paper wallets were ever actually claimed |
| 406 | +* For those wallets that go forever unclaimed, this essentially creates a permanent "burn" of both Lovelace and the native assets of the project; less than ideal |
| 407 | + |
| 408 | +By utilizing this framework, projects can have accurate, measurable analytics into the success of various real-world |
| 409 | +marketing and event efforts: Proof of Onboarding. |
| 410 | + |
| 411 | +## Path to Active |
| 412 | + |
| 413 | +### Acceptance Criteria |
| 414 | + |
| 415 | +- [X] Demonstrate a working MVP |
| 416 | +- [X] Open source an MVP example of token faucet [server-side code](https://github.com/HOSKYToken/poo-genericClaim) |
| 417 | +- [X] Receive feedback and iterate based on community feedback |
| 418 | + |
| 419 | +### Implementation Plan |
| 420 | + |
| 421 | +- [X] VESPR Mobile Wallet supports the Proof of Onboarding Protocol. |
| 422 | +- [X] Yoroi Mobile Wallet supports the Proof of Onboarding Protocol. |
| 423 | +- [X] HOSKY Project has released an open source server-side implementation software that may be used as a proof of concept for any interested projects. |
| 424 | +- [X] Multiple projects at multiple, global events have successfully deployed Proof of Onboarding. |
| 425 | +- [X] Onboard additional wallet providers, server/service providers, and redemption methods. |
| 426 | + |
| 427 | +## Copyright |
| 428 | + |
| 429 | +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). |
0 commit comments