Mint in Detail

Developers guide to minting

To mint tokens, two transaction building functions - Contract and Issuance - are needed. The Contract transaction generates a JSON output that defines the token properties and metadata, and includes all the satoshis necessary for the token issuance transaction. The Issuance transaction spends the Contract UTXO as input and adds token scripts as outputs, effectively linking the contract metadata to the issuance transaction, resulting in the creation of the tokens.

Contract

To generate a Contract transaction, a JSON object containing token information is necessary. You can find a template of this JSON object in tokenSchemaTemplate.js.

ParameterDescriptionProperty

name

The token name

string

protocolId

The token template protocol identifier

string format of available token protocol templates

symbol

The token symbol

alphanumeric characters 1-64 length

description

The token description

up to 512 characters

image

The image URL

250x250 pixels (recomended)

tokenSupply

The amount of tokens to mint in the issuance

Any integer

decimals

Decimals indicate the formatting, e.g. decimals 2 for a dollar token with cents. Reference only

Integer not bigger than 8

satsPerToken

Satoshis to be used for each token. (value of 1 recommended)

Integer

legal

STAS legal terms

RFC 3986 JSON formatted

issuer

Issuer information

RFC 3986 JSON formatted

meta

Any extra data to indicate legals and terms.

RFC 3986 JSON formatted

The "protocolId" field should match the token template wanting to use in the issuance. This is to allow correct referencing from the contract JSON to the token script itself. See Issuance section on "protocol" for more information on how to choose the different token templates.

const tokenSchemaTemplate = {
    name: "Test Token",
    protocolId: "STAS-20", // SHOULD MATCH THE ISSUANCE PROTOCOL VALUE 
    symbol: "TESTTOKEN001", // REQUIRED
    description: "This is a test token",
    image: "Some Image URL",
    totalSupply: 10, // REQUIRED
    decimals: 0,
    satsPerToken: 1, // REQUIRED
    properties: {
      legal: {
        terms: "STAS, Inc. retains all rights to the token script. Use is subject to terms at https://stastoken.com/license.",
        licenceId: "stastoken.com"
      },
      issuer: {
        organisation: "string",
        legalForm: "string",
        governingLaw: "string",
        issuerCountry: "string",
        jurisdiction: "string",
        email: "string"
      },
      meta: {
        schemaId: "STAS1.0",
        website: "string",
        legal: {
          terms: "string"
        },
        media: [
          {
            URI: "string",
            type: "string",
            altURI: "string"
          }
        ]
      }
    },
  }

The contractUtxo holds the satoshis that will fund the token supply. The satoshi amount in the contractUtxo must meet a minimum requirement for the token(s) being minted, and any extra satoshis will be returned to the issuer address in the form of a change output. The paymentUtxo is used to cover the transaction fees for the transaction. You can pass in the tokenSchema as a JSON object, which will be added to the transaction output. The tokenSatoshis refers to the total amount of satoshis utilized in the tokenSupply that is multiplied against the satsPerToken

const contractHex =  await stasContract.signed(
    issuerPrivateKey,
    contractUtxo,
    paymentUtxo,
    paymentPrivateKey,
    tokenSchema,
    tokenSatoshis
)

After executing the function, you will receive a transaction hexadecimal representation that is now ready to be broadcasted to the miner.

You need to use the contract output #0 UTXO in the issuance function. The utility.js file includes a helper function that retrieves a UTXO object from a transaction hex. This function takes the transaction hex and output index value as arguments.

const {utility} = require(stas)

const contractUtxo = utility.getUtxoFromTx(contractHex, 0)

The contract function is completed and now can move onto issuing the tokens!

Issuance

The issuance function is responsible for generating the transaction that issues the tokens. You can set any amount of satoshis per token during issuance. However, the library will verify that the total token supply and the satoshis per token correspond to the value in the contract UTXO.

Tokens can be issued as single or multiple outputs, in the case of splittable tokens. However, for non-splittable tokens, each token will be issued as a separate output since they cannot be divided or combined with other scripts of the same data value.

Here is an example of the issue data array.

const issueInfo = [{
		addr: "Some address string",
		satoshis: 100,
		data: ['STAS CUSTOM DATA', 'STAS CUSTOM DATA 2', 'STAS CUSTOM DATA 3']
}]

In this example, we are issuing 100 tokens to a single address and incorporating three custom data elements into the token script. The data field can accept an array consisting of string values. Each element of the array will be transformed into a hexadecimal data chunk and appended to the token script in ASM format. This method facilitates the separation of each data element with a space while in ASM format.

We can also distribute tokens to multiple addresses, as illustrated in the following example:

const issueInfo = [{
       addr: "Some address string ONE ",
       satoshis: 50,
       data: ['STAS CUSTOM DATA', 'STAS CUSTOM DATA 2', 'STAS CUSTOM DATA 3']
    },
    {
	addr: "Some address string TWO",
	satoshis: 50,
	data: ['STAS CUSTOM DATA', 'STAS CUSTOM DATA 2', 'STAS CUSTOM DATA 3']
}]

IMPORTANT : It's crucial to note that when issuing splittable tokens and intending to merge them later using the merge and mergeSplit functions, the custom data must be identical across all token outputs in the issueInfo array. The UTXO scripts of tokens can only be merged if their data matches precisely. If the tokens will not be combined in the future, you may issue them with varying custom data. To restrict the merging capability of tokens for future use cases, consider issuing non-splittable token types since these cannot be merged on a script level. To learn more about splittable and non-splittable tokens, as well as additional information about available token templates, please refer to the Token Properties in Detail section.

When using non-splittable tokens, it is essential to ensure that the token supply and the satoshis per token match the number of outputs in the issuance transaction. The amounts need to evenly divisible from the contract Utxo satoshi amount.

const issueInfo = [
    {
		addr: "Some address string ONE ",
		satoshis: 1,
		data: ['STAS CUSTOM DATA FOR NFT1', 'STAS CUSTOM DATA 2 FOR NFT1', 'STAS CUSTOM DATA 3 FOR NFT1']
	},
    {
		addr: "Some address string TWO",
		satoshis: 1,
		data: ['STAS CUSTOM DATA FOR NFT2', 'STAS CUSTOM DATA 2 FOR NFT2', 'STAS CUSTOM DATA 3 FOR NFT2']
	},
    {
		addr: "Some address string THREE",
		satoshis: 1,
		data: ['STAS CUSTOM DATA FOR NFT3', 'STAS CUSTOM DATA 2 FOR NFT3', 'STAS CUSTOM DATA 3 FOR NFT3']
	},
    {
        ...
    },
    ...
]

In this example we are creating multiple tokens with unique custom data added for each output.

The issuerPrivateKey will sign for the contractUtxo, and a paymentUtxo is added to pay the transaction fees along with the corresponding private key. The final function arguments are as follows:

isSplittable : is a boolean value that is only necessary for token templates that have flags indicating whether the token can be splittable or non-splittable. This is applicable to protocol types such as "STAS" or "STAS-50". However, for token templates that do not have such flags, this argument is not relevant and can be ignored by passing "undefined" in its place.

symbol : is a string value representing the token symbol. For it to be considered valid, it must match the tokenId field specified in the contract JSON.

protocol : represents the token template used to issue the token and must be a string value, such as "STAS-20" or "STAS-789". It should match the token schema field value for "protocolId" to maintain correct referencing back to the contract JSON.

const issuanceHex = await stasIssuace.signed(
    issuerPrivateKey, 
    issueData, 
    contractUtxo, 
    paymentUtxo, 
    paymentPrivateKey, 
    isSplittable, 
    symbol, // SHOULD MATCH THE CONTRACT JSON SYMBOL VALUE
    protocol
)

After executing the function, you will receive a transaction hexadecimal representation that is now ready to be broadcasted to the miner.

Last updated