Minting a Token
This documentation provides a high-level overview of how the protocol works. While the core concepts and flows are accurate, certain implementation details and design choices may evolve over time as the system matures. Please treat this as a conceptual guide rather than a source of exact specifications.
TLDR: Token issuers on Spark mint new tokens by generating token metadata and linking it to Spark leaves. These minting operations undergo validation by Spark Operators (SOs) to ensure compliance with issuance policies. Once validated, SOs store and track the token metadata as part of Spark state.
Minting on Spark is the process of generating new tokens and injecting them into circulation. On Spark, token minting follows a specific lifecycle that ensures security and transparency.
The first step in this lifecycle is a Mint Transaction. Here’s how it works: an Issuer generates a Spark Token Transaction, signs it with their Issuer Private Key, and broadcasts it to a Spark Operator group (also known as a Spark Entity). This group verifies the signatures, signs the transaction themselves, and then propagates it to the LRC-20 Node Gossip Network (more on this later).
Think of it like a Cashier’s Check. A bank locks up a set amount of funds and issues a signed check that can be redeemed at any time, risk-free. Similarly, a Spark Issuer pre-signs a transaction input, ensuring that it can always be redeemed on Bitcoin L1, with zero risk of the funds becoming unavailable at exit.
Constructing and broadcasting a Token Transaction takes three steps for transfers and two steps for minting. For a full breakdown of the communication flow, refer to the Swimlane Diagram.
Step 1: StartTokenTransaction()
StartTokenTransaction is the first step where an issuer (via a wallet) signals to a group of Spark Operators its intent to Mint or Transfer funds. This step is non-binding—no funds are moved yet. Instead, it sets the stage for the Issuer and Spark Operators to agree on a Final Token Transaction by determining key transaction parameters, including revocation keys.
At this stage, a Sender or Issuer constructs a Partial Token Transaction, specifying the leaves they intend to spend and the public keys of the intended recipients. To prove authorization, they sign this partial transaction for each leaf they wish to spend, allowing the Spark Entity to verify their permission to proceed.
Sample Partial Token Transaction
Upon receiving the request, the Spark Entity validates and processes the transaction. As part of this process, it assigns a Revocation Public Key to each output—this key is crucial for revoking the transaction later when the receiver spends the created leaves. (For details on Revocation Key derivation and selection, see the section below.)
Next, the Spark Operator modifies the Partial Token Transaction and returns the Final Token Transaction, which includes additional parameters for each output:
Key Parameters
- Leaf ID: A shared reference that allows both the Wallet and Spark Operator to track the TTXO created by this operation.
- Revocation Public Key: Since each output corresponds to a Partially Signed Bitcoin Transaction (PSBT), it requires a unique, immutable Revocation Public Key for future spending.
- Withdrawal Bond & Withdrawal Locktime: Immutable parameters that define the conditions for a valid unilateral exit transaction of this leaf to Bitcoin L1.
Step 2: SignTokenTransaction()
SignTokenTransaction is the next step. Once an SO receives and processes this request, the Token Transaction becomes irreversible.
At this stage, the issuer takes the FinalTokenTransaction from the previous step and generates a unique signature for each SO it wants to sign. It then sends an RPC call to each SO individually.
Each Spark Operator validates the request and, if valid, responds with the revocation keyshares for each spent leaf. Additionally, the SO signs the transaction and sends this signature to an LRC-20 node, which propagates it across the LRC-20 Gossip Network.
Once a threshold of SOs have signed and responded, the issuer can now derive the Revocation Key.
Step 3: FinalizeTokenTransaction()
The final step is for the issuer to send the Revocation Key it derived to each Spark Operator involved in the transaction. (For Mint operations, this step is unnecessary since mint inputs are not tied to a Revocation Key.)
At this point, the input leaves are officially revoked once the SOs communicate this update to their watchtowers. This make sure that the receiver of the funds can be confident that the sender cannot later attempt to double-spend the revoked leaves by broadcasting an outdated transaction on-chain.