NFC Specification


When a card taps a phone without a corresponding app installed, the NFC feature should open a web page showing a helper app (i.e., a mobile wallet) to install for interacting with the card.

However, much more than that is possible. For example, we can show a deposit address and display the balance for a SATSCARD, something we already do for OPENDIME® USB products.

Therefore, a dynamic NDEF response is desired.

NDEF Contents

URL Details

Example: + DYNAMICPART </br> The dynamic part is: u=S&o=3&r=bcajrh2jdk&n=01020304050607&s=fefb...00






Message to be Signed

The dynamic portion is the message being signed. It consists of everything up to and including the s=.

Special States


Decoding URL

On the server side (or caller’s Javascript, in-browser if possible), we will recover the public key by brute-forcing up to 4 possible values for the public key compared to the bech32 address fragment (or TAPSIGNER: pubkey hash) provided.

For SATSCARD, if the bech32 address is on testnet, additional comparisons may be required as the URL does not encode testnet status explicitly.

CBOR Command

Code For Decoding

From ../cktap, see file which implements full decode and verification, including address recovery or card ident recovery.

>>> from cktap.verify_link import url_decoder
>>> sc='u=S&o=0&r=vekusqj5&n=8334bd83e0bb7b25&s=4d868754a6e22172977ded6b12fbf05c0b8fe16194159373125e247f4f27811d6e6fe17ef65a050799e138305239ddcb97ad124cf1ae47c45ed8dd7f875626fe'
>>> url_decoder(sc)
{'addr': 'bc1q7h0u5yn8y4pajn94ze4gnhz487c8ysvekusqj5',
 'is_tapsigner': False,
 'nonce': '8334bd83e0bb7b25',
 'sealed': True,
 'slot_num': 0,
 'state': 'Sealed',
 'tampered': False

>>> from cktap.utils import card_pubkey_to_ident
>>> card_pubkey_to_ident(b'\x02'*33)