#99
ActiveWallets

Proof of Onboarding

Created on  by Adam DeanCarl and Alex Dochioiu

Abstract

Since at least 2021 when Cardano entered the Mary Era and implemented Native Assets, projects and creators building on the network have sought a means to distribute their tokens efficiently to users. Of particular frustration has been the ability to onboard new users at real-world events. Solutions for this historically have been to create and preload "paper wallets" where a seed phrase and accompanying password is generated by the project, pre-populated with tokens and ADA, and then delivered over to attendees of said event.

The creation of this addendum to the CIP-13 Cardano URI scheme seeks to minimize this friction and take advantage of existing technology to enable a new era of user onboarding, particularly at real world events through the use of a defined URI scheme enabling instant and frictionless communication between a project's "token fountain" and the user's wallet to reward, incentivize, and onboard new users easier than ever.

This CIP defines an extension to the CIP-13 URI Scheme as well as an API specification to facilitate and streamline communications between wallets and project servers.

Motivation: Why is this CIP necessary?

By leveraging the power of Cardano-specific URIs (CIP-13) and the modern technological advances of mobile devices and wallets we can provide a framework for Cardano projects to attend real world events, incentivize or reward attendees via their Native Assets, and have facts and figures to help support and analyze the impact that their attendance had (Proof of Onboarding).

Specification

CIP-13 Cardano URI Extensions

Distributing Native Assets (and/or ADA) to attendees of IRL events has historically been a pain point in the ecosystem. Some implemented solutions have included: Pre-generating wallet seed phrases and pre-populating these wallets with a minimum amount of ADA as well as the desired Native Assets, (re)creating token fountain/faucet designs which can be cumbersome and not user-friendly to instruct individuals to install a wallet, visit a website, enter a code and claim tokens.

The Cardano Token Claim URI schema is proposed to allow wallets (particularly mobile wallets) to implement a QR-friendly URI structure allowing for easy onboarding and distribution of Native Assets and/or ADA to individuals in a variety of situations but not least of which being at IRL events specifically tailored and geared to onboarding new users to the ecosystem.

Examples:

<!-- Token Claim URIs -->
<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=consensus2023">Claim $HOSKY</a>
<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io%2Fconsensus23&code=ABC123">Claim $HOSKY</a>
<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=ABC123&invoice=123456">Claim NFTxLV Commermorative NFT!</a>

ABNF Grammar

  • For a token claim URI (authority = claim), a versioning path, a faucet_url and a required code.
  • Additional query parameters may be provided and should be passed through to the provided faucet_url without modification.
cardanourn = "web+cardano:" claimtokenref

claimtokenref = "//claim" claimversion claimquery
claimversion = "/v1"
claimquery = ( "?" claimurl) ( "&" claimcode)
claimurl = "faucet_url=" text
claimcode = "code=" text

Token Claim URI Queries

All arguments for Token Claim URIs should be URL-encoded

Version 1 URIs

Version 1 URIs must include a faucet_url and a code as required parameters.

URIs may include additional arguments to suit the needs of the project's faucet API.

Handling Token Claim URI Queries

The token claim URI should consist of a required versioning path (i.e. /v1) as well as one or more required or optional URL-encoded arguments.

All Token Claim URIs must include a URL-encoded faucet_url argument as well as a code argument.

The wallet provider should send a POST request to the provided Faucet URL that includes:

  • The change/receipt wallet address of the user
  • Any additional arguments specified in the URI as key: value pairs

Example:

URI: web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io%2Fconsensus23&code=ABC123
Version: 1
URL: https://claim.hosky.io/consensus23
CODE: ABC123
JSON POST Data:
{
  "address": "addr1abc...xyz",
  "code": "ABC123"
}
Note on the address field

The wallet should always send the recipient address in bech32 format. If a particular token faucet implementation wishes to restrict or limit access to their faucet based on staking key or individual wallet address, this should be handled at the server end.

Supported Addresses

  • Shelley-era enterprise address consisting of only a payment key
  • Shelley-era staking address consisting of a payment and staking key
Note on the code field

The code is required. Specifying a code allows for reliable tracking and/or limiting of claims to the faucet host. Codes can be used to identify attendees of particular events (i.e. CODE = consensus2023) or can be a unique, one-time code per user (i.e. CODE = abc123xyz987). In this way we leave the code to be flexible to match a variety of analytical use cases depending upon the needs of the implementing project.

Security Considerations

  1. Wallets should prompt/warn users prior to sending potentially sensitive information (wallet address + code) via the token claim URI. An informational pop-up or confirmation modal should be displayed to users such as: We are about to send your address and code 123456 to https://claim.hosky.io. Are you sure you want to proceed?

Process Flow

The envisioned process flow for the POO Protocol is as follows:

  1. The project set asides some amount of budget (tokens + Lovelace [minUTxO]) for a given marketing push or IRL event
  2. If desired, one or more codes are generated to help track and analyze claiming figures
  3. QR Code(s) may be generated, printed, and otherwise displayed or given to users during the course of events
  4. Users scan the code with their mobile light wallet
  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)
  6. The project API returns a documented status code indicating the success or failure of the operation
  7. If a successful status is detected and returned, the project issues tokens to the specified address per their campaign settings

URI Format

The URI format consists of the CIP-13 web+cardano:// scheme, followed by the claim authority, then a version path.

NOTE: ALL ARGUMENTS SHOULD BE URL-ENCODED

Version 1

Version 1 URIs must include /v1 as the path of the URI.

Version 1 URIs must include two required arguments:

  • faucet_url as a fully-typed URL (i.e. https://claim.hosky.io)
  • code as either a campaign identifier or unique, one-time use code

Version 1 URIs may include additional query parameters that should be passed through to the api server.

Version 1 Examples:

<!-- A Cardano Claim URI with campaign identifier code -->
<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=consensus2023">Thanks for attending Consensus 2023!</a>
 
<!-- A Cardano Claim URI with unique, one-time use code -->
<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=dff6508d8dfb4e128fd67e9ff54af147">Claim your $HOSKY now!</a>
 
<!-- A Cardano Claim URI with a campaign-specific code and optional user_id argument -->
<a href="web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.hosky.io&code=NFTxLV2023&user_id=Idjiot1337">Get your $HOSKY!</a>

Wallet Requests

Light wallets that detect and support web+cardano URIs as well as mobile wallets who detect either a QR code or other link with this format should parse the URI and send a POST request to the specified URL containing a JSON payload including:

  • The user's wallet receive address
  • The code
  • Additional URI query parameters passed through

Examples

Faucet URL + Campaign Code
  • URI: web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=NFTxLV2023
  • Faucet URL: https://claim.nftxlv.com
  • POST JSON Data:
{
  "address": "addr1abc...xyz",
  "code": "NFTxLV2023"
}
Faucet URL + Unique Code
  • URI: web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=NFTxLV2023
  • Faucet URL: https://claim.hosky.io
  • POST JSON Data:
{
  "address": "addr1abc...xyz",
  "code": "ABC123"
}
Faucet URL + Campaign Code + Custom User ID
  • URI: web+cardano://claim/v1?faucet_url=https%3A%2F%2Fclaim.nftxlv.com&code=NFTxLV2023&user_id=Adam1337
  • Faucet URL: https://claim.nftxlv.com
  • POST JSON Data:
{
  "address": "addr1abc...xyz",
  "code": "NFTxLV2023",
  "user_id": "Adam1337"
}

API Server Response Codes

The API server is expected to return one of the following defined status blocks in application/json format. Any other responses from the API server should be considered invalid and discarded or display an error.

The expected API that any token fountain implementation should follow and wallet integrators should expect is documented on Swagger!

Successful Responses

Valid (200)

First Successful Request

{
  "code": 200,
  "lovelaces": "2000000",
  "queue_position": 23,
  "status": "accepted",
  "tokens": {
    "a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235.484f534b59": "29433292000000"
  }
}
Valid Queued (201)

Subsequent Successful Request (Address + Code Match) prior to token distribution

{
  "code": 201,
  "lovelaces": "2000000",
  "queue_position": 1,
  "status": "queued",
  "tokens": {
    "a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235.484f534b59": "29433292000000"
  }
}
Valid Complete (202)

Subsequent Successful Request (Address + Code Match) after token(s) are distributed

{
  "code": 202,
  "lovelaces": "2000000",
  "status": "claimed",
  "tokens": {
    "a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235.484f534b59": "29433292000000"
  },
  "tx_hash": "TX1234"
}

Error Responses

Bad Request - Invalid Address (400)

The provided address is not a valid Cardano address

{
   "code": 400,
   "status": "invalidaddress"
}
Bad Request - Missing Code (400)

No code was provided in the request

{
   "code": 400,
   "status": "missingcode"
}
Bad Request - Invalid Network (400)

The wallet provided is from the wrong network (testnet/mainnet)

{
   "code": 400,
   "status": "invalidnetwork"
}
Invalid - Not Known (404)

The specified code does not exist

{
  "code": 404,
  "status": "notfound"
}
Invalid - Already Claimed (409)

An address was already used (if not code present) or the code presented was found but the address did not match

{
  "code": 409,
  "status": "alreadyclaimed"
}
Invalid - Expired (410)

For time-limited fountains, a code of 410 means that the period for redemption has expired

{
  "code": 410,
  "status": "expired"
}
Invalid - Too Early (425)

For time-limited fountains, a code of 425 means that the period for redemption has not begun yet

{
  "code": 425,
  "status": "tooearly"
}
Invalid - Rate Limited (429)

Rate limiting settings and details are left to the discretion and implementation of individual projects. A status code of 429 or this status response should be considered as a rate limiting response.

{
  "code": 429,
  "status": "ratelimited"
}
Server Error (500)

Implementations should of course be prepared to handle situations where a server is non-responsive for any reason and be prepared to handle any other, non-specified error codes including 500 codes.

Versioning & Modification Rules

If there is sufficient justification in the future for modification of this standard to the point that a "Version 2" would be necessary, those changes MUST be submitted as a new, separate CIP to this repository and follow all applicable CIP standards for acceptance. Examples of "major" changes that might justify a new version of this CIP include: fundamentally altering the URI structure, adding or removing a required field, or any other non-backwards compatible changes to the Process Flow.

Minor changes for grammar, clarity, or functionality that fall within the scope of "Version 1" of this document may be made by editing this document directly. Such changes include: grammatical or exposition changes to improve readability or clarity of communication, improvements to documented code examples, additional or optional server response information, etc.

Rationale: How does this CIP achieve its goals?

By creating a well-defined standard for both a CIP-13 URI scheme and the expected API response(s) we can create a framework that both wallets and projects can utilize to encourage and onboard new users into the ecosystem via Native Asset incentive models without needlessly and constantly reinventing the wheel for each product or project.

Furthermore, the aforementioned "paper wallet" technique has many drawbacks including:

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

By utilizing this framework, projects can have accurate, measurable analytics into the success of various real-world marketing and event efforts: Proof of Onboarding.

Path to Active

Acceptance Criteria

  • Demonstrate a working MVP
  • Open source an MVP example of token faucet server-side code
  • Receive feedback and iterate based on community feedback

Implementation Plan

  • VESPR Mobile Wallet supports the Proof of Onboarding Protocol.
  • Yoroi Mobile Wallet supports the Proof of Onboarding Protocol.
  • HOSKY Project has released an open source server-side implementation software that may be used as a proof of concept for any interested projects.
  • Multiple projects at multiple, global events have successfully deployed Proof of Onboarding.
  • Onboard additional wallet providers, server/service providers, and redemption methods.

This CIP is licensed under CC-BY-4.0.