# Ğchange QRcode RFC Status: draft Aim: scan QRcodes in Ğmarkets with Ğecko, to pay securely and easily Depends on: [unsigned-varint](https://github.com/multiformats/unsigned-varint) ## QRcode content * magic number (3 bytes) * Data type (uvarint) * Price type (uvarint) * Recipient pubkey (32 bytes) * Amount * Data ### Magic number `0x831614` (this was generated randomly) This number could be incremented in later versions of the protocol. ### Data type * 0: None (0 bytes) * 1: Plain text (until the end) * 2: Ğchange ad (16 bytes) Data is placed at the end in order to enable parsing the message even if the client doesn't know the data type. ### Price type `Value & 0b1111` (the 4 LSB): amount length, in bytes `Value >> 4` (all the other bits): * 0: Ğ1, no amount (free price) (then, amount can be empty) * 1: Ğ1, unit (cent) * Amount (uvarint) * 2: Ğ1, UD * Amount float (uvarint) * Amount 10 opposite exponent (uvarint) _example: 12.34 becomes 1234×10^-2; 120 becomes 120×10^0_ Amount length is specified to enable parsing the message even if the client doesn't know the price type. ### Amount Amount value is encoded in cents, in the current base. ## Python decoding example ``` #!/usr/bin/env python3 from io import BytesIO import base64, base58, varint ## BytesIO adds a stream interface to bytes ## Example: qr = BytesIO(bytes.fromhex("8316140212c28e52e034ecaf684fa3e5d755db519074f27ad086bddffd26b386e55f3b623ca01f0177c0f8ce5f6a69764c7bc10263ec")) ## Read from a file: # qr = open("qrcode-AXfA-M5faml2THvBAmPs.bin", "rb") ## Check magic number assert qr.read(3) == b"\x83\x16\x14" ## Read data type data_type = varint.decode_stream(qr) ## Read price type raw_price_type = varint.decode_stream(qr) price_type = raw_price_type >> 4 amount_len = raw_price_type & 0b1111 ## Read pubkey pubkey = qr.read(32) pubkey_b58 = base58.b58encode(pubkey) print("Pubkey: {}".format(pubkey_b58)) ## Read amount if price_type == 0: # Free price, ignore amount qr.read(amount_len) print("Free price") elif price_type == 1: # Units amount = varint.decode_stream(qr) print("Price: {} Ğ1".format(amount/100)) elif price_type == 2: # UD amount_n = varint.decode_stream(qr) amount_e = varint.decode_stream(qr) amount = amount_n * 10 ** -amount_e print("Price: {} UD_Ğ1".format(amount)) else: qr.read(amount_len) print("Error: unknown price type, ignoring price") ## Read data if data_type == 0: # No data data = None print("There is no data") elif data_type == 1: # Plain text data = qr.read() print("Data:") print(data) elif data_type == 2: # Ğchange ad data = base64.urlsafe_b64encode(qr.read(16)) print("Ğchange ad ID: {}".format(data)) ```
{}