First of all, I'm not an expert on SLP. I just wanted to figure out how SLP tokens work and these are my notes while doing that.

Please refer to the original document for details.

There are a few token types planned, this is the description of Token Type 1. As of this day (Nov 2019) I don't think there are any other token types.

SLP tokens don't have any central authority point, so anyone who can craft a special transaction on the Bitcoin Cash network - can create own SLP token using "Genesis" transaction type.

SLP token is created with a "Genesis" transaction, like this:

(See also: What's inside a Bitcoin Cash transaction for a complete diagram of how BCH transaction really looks like)

All outputs are sent as the regular transaction outputs. (OP_RETURN output is kind of like a "comment" to a transaction. This "comment" would "contain" all the information about SLP tokens in this transaction.)

With the exception of OP_RETURN you need to send some small number of satoshis (546 satoshis = US$0.001 (@$240/BCH) "dust" - the minimal number of satoshis you can send) to the output.

First output is the specially crafted string (starting with OP_RETURN) of type "Genesis":

Minting "read.cash coin" (ticker: RDCS) token with 100'000 base units of the token, divisible up to 2 places, like USD = 1000.00 tokens

"Length of the next field" is actually a push operation, which mostly coincides with the length of the next field, see here.

"Mint baton" is a sequential number ("vout", starting with "0" -> OP_RETURN) of the output that allows this output to create or mint additional tokens later. If you omit the baton vout (use 4c00 to omit any field = "zero push") - that means that the initial mint is final and no tokens will be created anymore.

After you broadcast this transaction - you'll get its TX ID. It's now the token_id of this SLP token.

"lokad_id" is the string "SLP" followed by one zero byte.

Now the receiver at vout "1" gets 100000 "base units" of your token (1000.00 tokens).

So, now the receiver of tokens got 1000.00 tokens, let's send them.

If you don't understand why 1000: the receiver got 100'000 "base units". You have selected 2 decimal places during "genesis", so take 100'000, move the decimal point two places to the left and you get: 1'000.00

Another example: Bitcoin Cash has a final circulation of about 21 million BCHs, but it's divisible up to 8 places, so it has a total final circulation of 2'100'000'000'000'000 "base units" named "satoshi" - that's "two quadrillion one hundred trillion satoshis".

Back to sending, you need to build and broadcast this transaction (you can have one or more inputs and up to 19 outputs):

...and the OP_RETURN this time is:

Now, "receiver 1" (vout=1) gets 1E3F (77.43 tokens) and receiver 2 gets DFAC (572.60 tokens). The rest 349.97 tokens are burnt (destroyed) (1000.00-77.43-572.60=349.97).

Again, token_id is the genesis transaction hash.

You always send an integer number of base units. So, if you wanted to send 125.50 US Dollars, you'd actually need to send 12550 US cents.

How do you verify that the user has enough tokens to send? You just go to the parent transactions (look at TXID+vout of each input and verify correctness of their OP_RETURN's (they can be "send", "mint" or "genesis" transactions).. and then you go to their parent inputs.. and theirs... as far as you want to go, best up to the "genesis" transaction).

Miners do not enforce SLP rules for the transactions (but see below about "double spending"). Miners will include incorrect SLP token transactions, which are signed with correct private key of spender, into the blocks, effectively burning tokens according to SLP rules. It's up to the users of SLP tokens to verify the correctness. Thankfully, the protocol is pretty simple to verify.

Ok, so you've done the initial mint ("genesis") and now you want to create (mint) some more tokens.

You need to spend the UTXO (unspent transaction output) of the transaction that currently has the "mint baton" from the genesis transaction (or from the previous mint operation, see further).

...and again, OP_RETURN is:

Again, just like with the "Genesis" transaction - if you omit the mint baton - nobody gets to mint this token anymore.

Now the receiver at vout "1" gets 100'000 "base units" of your token (1000.00 tokens).

In the end you get something like this:

How the SLP token goes. A spend can spend from many previous UTXOs, just like the usual transaction

Now, you can go backwards through this graph and verify that every parent transaction was valid - that proves that you now have the SLP tokens.

There's one more type of transaction - that is "commit".

Basically, it's a transaction that states that "at this point in time these SLP transactions for my token were valid, but those weren't valid".

To do that you (as a token creator) commit the hash of your "merklix" tree (don't ask, I don't know) using one more special transaction type and the URL where the users can find the tree.

As far as I understand, this is an optional step that kind of helps SLP token processors.

You'd still need to verify all transactions to ensure that the token issuer is not cheating, so it's better to do something like what SLPDB does, that is to just verify each transaction throughout the history, rather than trusting the issuer with their "commit". It seems certainly easier to trust the commit, but probably software like SLPDB does already build this index too and have the API for getting it and have absolutely no reasons to cheat.

This part of the specification is a bit a mystery to me for the reasons stated in the previous paragraph.

Since, all of the OP_RETURNs that contain information about the token movements are attached to UTXOs (unspent transaction outputs) - miners enforce the regular rules that this UTXO can only be spent by one spending transaction. So, SLP tokens are protected from double spending by the same rules that protect BCH.

Here's a paragraph from the specification:

We emphasize the point, again, that the message has to be perfect in its entirety. For example, if a transaction has 5 outputs, and the fifth output has only 7 bytes instead of 8, then the previous 4 outputs effectively burn the tokens because the entire transaction is invalid.

It wasn't immediately clear to me whether this really "burns" tokens or just marks the transaction as "invalid", meaning that I can use the the parent transaction again to "correctly" spend it, until I wrote the previous paragraph on double spending. If you've spent the UTXO incorrectly (according to SLP, but signed with the valid private key), you're out of luck - miners won't let you spend it again and your tokens are now "burnt" (destroyed).

One more important part is the addresses. By convention you use the simpleledger: prefix in place of bitcoincash: in the addresses where you can send the SLP tokens. This is mostly done to prevent sending tokens using wallets that don't understand SLP.

If you'd try to spend from the UTXO that is linked to the OP_RETURN which has some SLP tokens using simpleledger: address and non-compliant wallet - your transaction just won't go through, even though the letters and numbers after the prefix are the same addresses as in regular BCH.

If you find any errors - please let me know in the comments. Thank you!