Introduction
There was a discussion on Slack about the Stellar QR code format. You can find it archived here.
I will try to summaries this discussion and add some of my own ideas.
NOTE: The formats proposed here are the result of a brainstorming session and will need multiple iterations before being production ready. The goal of this post is to start the discussion about it, learn about multiple use cases and find the best solution.
Use cases
QRcodes/URIs/NFCs/... can hold any kind of data and can be used to solve different problems for Stellar. One of the use cases is to store secret keys for easier backups and later imports. In this post I will mostly focus on the format for payments/invoices. If you have an idea for the secret key import/export format or other use cases please post it in this thread. It would be great to have them all in one place.
In the end we may end up with one über format that is able to hold information about payments, secret key backups and other use cases in one structure.
Online vs Offline transaction signing
I see two main use cases for sharing Stellar data through QR codes/URIs/NFCs:
- The user wants to send an asset to someone on the Stellar network and needs their public key/federation address.
- The user is checking out in a shop and need to pay for his purchase.
In the first case you only need the public key of the receiver and maybe information about the asset type, amount and a memo. When you receive the information your wallet builds a transaction and publishes it on the stellar network.
But int the second case the point of sale (POS) system can already prepare the transaction for the user, transfer it to their phone over NFC and the user just needs to sign it and send it back. In this case the user doesn't need to have an internet connection and the purchase can be done much faster as the point of sale system has control about publishing the transaction.
Format vs protocol
When I talk about the format I mean a set of key/value pairs that are used to exchange information between devices/users. If the same keys are part of a json structure in a QR code or attributes in an URI I consider them to be the same format. I think that we should not enforce json on everything as it is not a natural fit.
JSON can be used for QR codes and NFC (NDEF), but the same keys can be translated into attribute/value pairs in an URI. We would not gain anything by enforcing json in an URI as the wallet still needs a custom URI parser to extract the JSON data.
The protocol is a set of messages that are exchanged. During an NFC POS offline payment we would need to exchange multiple messages between the POS system and mobile phone. First the POS system would send a request to the mobile phone to sign the transaction and then the mobile phone needs to send the signed message back. Afterwards the POS system can send a confirmation over NFC. The formats for all this messages would be defined as part of the NFC POS protocol.
In some other cases the protocol would just consist of one message/format (QR code with information about the payment).
It does not make sense to use all formats for all protocols. It would be extremely inefficient to use QR codes to exchange data about offline signing. NFC fits this use case much better.
Formats
I would prefer to keep the format as a flat set of key/value pairs. URIs for example don't support nesting elements and you would need to additionally encode them. You can always flatten out the structures with prefixes. For example:
{
'account': {'id': 2344,
'name': 'Stellar'}
}
would become
{
'account_id': 2344,
'account_name': 'Stellar',
}
Receiving payments
As Scott suggested on Slack, a really simple format to ask for payments would be:
{
'receiver': 'GCA4S3...',
'amount': '100',
'currency': 'XLM',
'memo': 'internal_tx_id_like_12839109'
}
Notice that this format is in JSON, but it can also be represented as an URI:
stellar:?receiver=GCA4S3...&amount=100¤cy=XLM...
that can be used as a link on a webpage. When you click it, it opens your wallet and prepares the transaction. Similar to torrent magnet links.
Another format, used by sacarlson's wallet is:
accountID : the public address of recieved funded account (optional as it is created with just seed ) value is a string of uncoded public address
seed : secreet seed of a recieved funded account value is a string of private seed that is optionaly encrypted
env_b64 : an envelope blob to be signed or transacted value is a string in base64 format of a tx envelope
amount : amount that would be sent in an invoice value is floating number
memo : a memo that will be attached to the invoice of the store name or item being purchased value is a string max 32 long
asset : type of asset that would be sent to the store from the invoice value is a string of an asset class
issuer : issuer of the asset that the store is expecting to recieve value is a string of a public address of the issure of an asset
destination : the public address of the store or person that is to recieve the invoice billed funds.```
sacarlson: quotes in my format are replaced with %22 and space is replaced with %20 to allow url link compatibility
And Johan suggested the following format:
invoice: {
asset: {
assetcode: 'USD',
issuer: 'address of issuer'
},
amount: '3.1415',
destination: 'seller*seller.com',
memo: {
type: 'MEMO_HASH',
data: 'de42425863ffbb12..'
},
message: 'Thank you for shopping at seller.com'
}
I prefer Johan's format, as the naming of keys is much clearer. Just maybe have 2 different destination types, for federated addresses and public keys. The wallet needs to handle them differently. And I would flatten out the structure like this:
type : 'invoice',
asset_code: 'USD',
asset_issuer: 'address of issuer',
amount: '3.1415',
destination: 'seller*seller.com',
memo_type: 'MEMO_HASH',
memo_data: 'de42425863ffbb12..'
message: 'Thank you for shopping at seller.com'
We still need to think about what kind of types we want (e.g. invoice, offline_invoice,...). In this case we can define also types for importing/exporting secret keys. We can have one type for plain text secret keys and another for encrypted keys.
Some protocols would consist of multiple messages, like the offline_invoice type and we will probably need sub types to distinguish between them.
Maybe it would be good to have an version field to specify the version of the format so we can introduce changes that are not backwards compatible at some point.
This was mostly a brain-dump of my ideas. But I think it's a good starting point for the discussion.