โจSRC20 on Bitcoin
BTC Stamp fungible token protocol - SRC20 specification
Source: https://github.com/hydren-crypto/stampchain/blob/main/docs/src20.md
SRC-20 Tokens
SRC-20 Specifications have changed protocol specifications as of block 796,000. SRC-20 transactions are now created directly on BTC and are no-longer supported as Counterparty transactions. SRC-20 mints, deploys, and transfers are all free from an service fees with the exception of the BTC miners fee when done from a supported wallet.
SRC-20 is a bleeding edge specification modeled after BRC-20. Prior specifications of SRC-20 in its initial state were built on top of Counterparty transactions with specific requirements for an issuance transaction. The current specification as of block 796,000 encodes the SRC-20 transaction directly onto BTC and does not use Counterparty. Any SRC-20 transactions created on Counterparty after block 796,000 will be invalid. Counterparty was used as a proof of concept as we designed a direct to BTC method which optimizes the transaction size and reduces cost of SRC-20 transactions.
Specifications
SRC-20 Tokens must conform to these required fields or a Bitcoin Stamp Number will not be created, the transaction will not be considered a valid SRC-20 transaction, and they will not appear in the Bitcoin Stamps Protocol index / API.
SRC-20 transaction must be signed and broadcast onto BTC by the address that holds the SRC-20 token balance as it acts as a means to authenticate ownership. Both the source and destination addresses are embedded into the BTC transaction which is created by the users wallet. The SRC-20 reference wallet will ensure you are creating the proper transaction until support can be integrated into more broadly distributed wallets such as Hiro. Please use extreme caution if signing transactions created by a third party.
DEPLOY
MINT
TRANSFER
If the amount specified to be transferred exceeds the balance held (which would be determined by the latest state of an Indexer), then the transfer will be deemed invalid.
SRC-20 Token Requirements
Tokens must be 1-5 characters in length.
Allowed characters: a. Any word character (alphanumeric characters and underscores) b. Special characters: ~!@#$%^&*()_+=<>? c. Most printable emojis in U+1F300 to U+1F5FF
Disallowed characters: a. Non-printable Unicode characters b. Quotation marks: " ` ' outside of regular json delimiters c. Special characters not present in (2b, 2c) including , in numeric fields
Only numeric values are allowed in the "max", "amt", "lim" fields
Other Qualifications:
The third multisig pubkeys must be to a valid Keyburn address
not case sensitive DOGE=doge
max mint/transfer/lim amount: uint64_max 18,446,744,073,709,551,615 (commas not allowed, here for readability only)
max decimals: 18 (default - no need to specify unless a lower precision is desired)
json strings are not order sensitive
json strings are not case sensitive
MAX, LIM fields are integers only
AMT field is a decimal up to uint64 max with 18 decimals
Must be a valid CP transaction for transactions prior to block 796,000 have 0 assets issued, locked, and not divisible
Must be a valid BASE64 as decoded by Python 3.9 base64.b64decode(base64_string prior to block 796,000
Balance Calculations
Mints over the limit are capped - user will receive the limit amount if the token has not exceeded the max value
Deploys to the same tick which are previously deployed are invalid
Negative mints and transfers are invalid
If a mint is within the limit, but not within the max it is capped at the max value
Any mint where max has already been exceeded is invalid (overmint)
Any transfer over the users balance at the time of transfer is considered invalid and will not impact either users balance
if wallet x has 1 KEVIN token and attempts to transfer 10000 KEVIN tokens to address y the entire transaction is invalid
SRC-20 Token Example JSON Strings
INVALID tokens will not be created in the Bitcoin Stamps Protocol index or API, and the transaction will not be considered a valid SRC-20 transaction. Any further modifications to the standard must be designed around backwards compatibility.
Allowed Unicode Chars for Tick Field
Emoji_Presentation: This property includes all characters that are defined as emojis and have a distinct emoji-style appearance. These characters are intended to be displayed as colorful pictographs, rather than black-and-white text symbols. Examples include face emojis (๐, ๐, ๐), objects (๐, ๐, ๐), and symbols (โค๏ธ, ๐ซ, โฐ).
Emoji_Modifier_Base: This property consists of characters that can be modified by emoji modifiers, such as skin tone modifiers. These characters usually represent human-like figures (e.g., ๐ฉ, ๐จ, ๐คณ) and can be combined with emoji modifiers to represent variations in skin tone or other attributes.
Emoji_Modifier: This property contains characters that can be used to modify the appearance of other emojis, particularly the ones classified as Emoji_Modifier_Base. The most common example is the skin tone modifiers (๐ป, ๐ผ, ๐ฝ, ๐พ, ๐ฟ) that can be applied to human-like emojis to represent different skin tones.
Excluded Unicode Chars for Tick Field
These chars are excluded from the allowed chars list because they are not printable, and are not allowed in the tick field. Tokens with these chars will not be created in Bitcoin Stamps Protocol index or API, and the transaction will not be considered a valid SRC-20 transaction.
Emoji_Component: Characters that are used to create more complex emojis, such as skin tone modifiers and hair components. These characters are not emojis on their own but can be used with other emojis.
Extended_Pictographic: This includes additional pictographic characters not covered by Emoji_Presentation but can still be considered emojis.
to apply an emoji modifier it would take up 2 chars, and be added directly after the emoji from emoji_presentation. I suspect the web browser interprets that. kind of cool, didn't know how those worked.
an ASCII character takes up only one byte, while an emoji can take up to four bytes.
SRC-20 BTC Transaction Specifications
The owner of the first input is considered the owner / source of the transaction | vin[0].prevout.hash[::-1]
The first vout
output 0
is the destination address for a transfer "address": "bc1q4lwvx2380r4axmzgt8rnqxa5cvktt8unqlnka6"
For mint and deploys vout-0
is the minter/deployer address
The components of the multisig ScriptPubKeys
are:
1
: This is the number of required signatures for the transaction to be valid. Always 1 (of 3) for SRC-20 (1 sigop)03c46b73fe2ff939bea5d0a577950dc8876e863bed11c887d681417dfd70533e51
: This is the SRC-20 encoded data039036c8182c70770f8f6bd702a25c7179bfff1ccb3a844297a717226b88b976cc
: This is the SRC-20 encoded data020202020202020202020202020202020202020202020202020202020202020202
: This is the hash that must be to a valid keyburn address.3
: This is the total number of public keys in the multisig script. Always (1 of) 3 for SRC-20OP_CHECKMULTISIG
: opcode
We will also use an additional mulisig script in the decoding example below. Additional multisig scripts may be added depending on the length of the JSON string.
Decoding the SRC-20 Bitcoin Transaction
Take the first two pubkeys from all present multisig scripts. In this example there are a total of 4 hex strings in the two scripts.
First we strip the sign and nonce bytes (first and last bytes from each string) which leaves.
The strings are then concatenated and decoded using ARC4 decoding, which uses the vin[0].prevout.hash[::-1]
as the signing key.
The output after ARC4 decoding is:
The first two bytes - in this example 0045
is the expected length of the decoded data in hex (less any trailing zeros) for data validation. This is required in order for the transaction to successfully parse and be indexed. Transactions without this value or a value that does not match the string length are considered invalid.
The next 7374616d703a
is the hexadecimal representation of stamp:
in lowercase - this is required for a valid stamp SRC-20 transaction
The remaining string is the SRC-20 JSON data.
Which UTF-8 decodes to:
{"p":"src-20","op":"transfer","tick":"STEVE","amt":"100000000"}
In order to minimize the transaction size spaces are not used in the serialized JSON string which is constructed by the SRC-20 reference wallet.
Compression
Compression and data serialization is supported in SRC-20 transactions. Previously SRC-20 was a JSON Strings encoded in BASE64 inside of a Counterparty issuance transaction. In some cases the json string was serialized and compression was utilized to minimize the size of the corresponding transaction. This is an important factor when indexing and validating prior SRC-20 transactions within Counterparty transactions, and will continue to be supported in current version SRC-20 transactions. However given the construction of the JSON string without spaces, and the fact that we are no longer encoding in BASE64 the transactiรon size benefits are minimal. This must be taken into consideration when parsing for transactions on chain.
An example of the serialization and compression:
Indexing for SRC-20 Transactions
SRC-20 transactions may be indexed directly from BTC for validation. Prior to block 796,000 this can be accomplihed using Counterparty API's to pull transaction details from valid issuances with a numeric asset with a valid json string encoded in base64 with the multisig scripts to a valid keyburn address. All transacitons on and after block 796,000 must be parsed directly from a BTC node. The specifications above must be followed including valid json strings and a valid Bitcoin Stamp transaction prefixed by 'stamp:'
Tick Length
Python sees the text length differently than Node.JS. In the following example we determine the char length using the python method.
Node: 'BULL๐'.length = 6
Python: len('BULL๐') = 5
Base64 and other Decoding Anomolies
Python and Node.JS handle base64 decoding differently. Prior to block 796,000 for CP based transactions which were base64 encoded this can have an impact on valid/invalid transactions. After block 796,000 for direct to BTC transactions which are ARC4 encoded this does not have an impact.
For example:
Transaction: c129cc8f13760fce63a42257dbe5dcdd0aad798f858f6b08968c7834c7a1bcc7
With base64 string: eyJwIjogInNyYy0yMCIsICJvcCI6ICJtaW50IiwgInRpY2siOiAiUElaWkEiLCAiYW10IjogIjExMTExIn0
This string is considered invalid in Python using base64.b64decode(base64_string)
and pybase64.b64decode(base64_string)
and in bash printf "%s" "{base64_string}" | base64 -d
because it is missing the end of line =
for padding / newline. The original indexer was written in python with these 3 checks so it is deemed invalid even though Node.JS interprets this string properly. Padding was attempted in prior iterations to attempt to include improperly formatted base64 strings into BTC Stamps protocol however since it is not possible to properly determine the location for padding in all cases these were simply deemed invalid to remove malformed data.
Also, Transaction f3a8df9f71bd195b43186c669666732fa86623e2d2f9633cf663b32e5e417b69
at the time of block 796000 was parsing as an SRC-20 transaction when pulled directly off Bitcoin. However on 3 Counterparty nodes the transaction parsed as shown below. Due to the requirements of SRC-20 Transactions being a valid counterparty transaction prior to the specified block this transaction was deemed invalid. This may be a bug in Counterparty which was unable to be addressed for final validation so this was excluded. This is documented for future indexing validation. The original transaction was a Bitcoin Stamp, however the same Counterparty asset name was used for the second transacion was intended to be a JSON string for a SRC-20 token. This is against protocol specifications where a previously existing stamp on the asset cannot be changed.
Example SRC-20 JSON Validation
If the JSON string is not valid including it will be rejected from the index. This is a sample of the validation script. Any SRC-20 transactions that do not pass this validation are considered invalid transactions and will not impact user balances. This is the current method used for the indexer validation of JSON strings. Anything that does not pass this check will not get a valid BTC Stamp number and will not be indexed as part of SRC-20.
Last updated