About the author:
Daniel is CTO at rhome GmbH, and Co-Founder at Aqarios GmbH. He holds a M.Sc. in Computer Science from LMU Munich, and has published papers in reinforcement learning and quantum computing. He writes about technical topics in quantum computing and startups.
jrnl · home about list ventures publications LinkedIn Join my Slack

# Creating a custom Stellar token for free

I have recently created the Ludi token on the Stellar blockchain!

This short and concise guide goes through the process of creating such a Stellar token (or: Stellar asset) for basically free. Since I am in engineering, this will require you to know how to run a Python program, nothing else.

  1. Create a coinbase account This will require you to be at least 18 years old, have some kind of identification, and a phone number for verification. You will also have to add a payment method (I just added my credit card), which will be verified automatically by a small payment of a few cents.

  2. Get free Stellar tokens by watching some videos. This will require you to verify your account with your drivers license or personal ID. You can then watch the lessons here and earn in total 8 USD worth of Stellar Lumens.

  3. Create two accounts on the Stellar blockchain. First go to this link: https://laboratory.stellar.org/#account-creator?network=public. Then, generate a keypair for the issueing account, and save it, and generate a keypair for the distributing account. The distributing account is the interesting one at the end - this will be the account that has all your initial tokens. In the case of Ludi this was 1 trillion Ludi tokens. The public key always starts with G, the secret one with S.

  4. Fund the two accounts by sending 2 Stellar Lumens to each account from your coinbase account. Use the public key of each as the receiving address (starts with G).

  5. Create the asset itself using Python. For this, replace the secret keys with the correct ones in the code below and run it.

    from stellar_sdk import Asset
    from stellar_sdk import Keypair
    from stellar_sdk import Network
    from stellar_sdk import Server
    from stellar_sdk import TransactionBuilder
    
    server = Server(horizon_url="https://horizon.stellar.org")
    network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE
    
    issuing_keypair = Keypair.from_secret("SB..........")
    issuing_public = issuing_keypair.public_key
    distributor_keypair = Keypair.from_secret("SB...........")
    distributor_public = distributor_keypair.public_key
    
    distributor_account = server.load_account(distributor_public)
    ludi_token = Asset("ludi", issuing_public)
    
    trust_transaction = (
        TransactionBuilder(
            source_account=distributor_account,
            network_passphrase=network_passphrase,
            base_fee=100,
        )
        .append_change_trust_op(asset=ludi_token)
        .set_timeout(100)
        .build()
    )
    
    trust_transaction.sign(distributor_keypair)
    trust_transaction_resp = server.submit_transaction(trust_transaction)
    print(f"Change Trust Transaction Resp:\n{trust_transaction_resp}")
    
    issuing_account = server.load_account(issuing_public)
    payment_transaction = (
        TransactionBuilder(
            source_account=issuing_account,
            network_passphrase=network_passphrase,
            base_fee=100,
        )
        .append_payment_op(
            destination=distributor_public,
            asset=ludi_token,
            amount="1000000000000",  # 1T (other values possible too)
        )
        .build()
    )
    payment_transaction.sign(issuing_keypair)
    payment_transaction_resp = server.submit_transaction(payment_transaction)
    print(f"Payment Transaction Resp:\n{payment_transaction_resp}")
    
  6. You can now check out your asset on the Stellar chain! See here for the Ludi token for example.

  7. OPTIONAL: Buy a domain and set up more information, to make your project look more legit. Add it in the toml as described here and upload to your hosting under https://YOURDOMAIN/.well-known/stellar.toml. For Ludi, the toml file can be found here. Then, run the following code:

    from stellar_sdk import Keypair
    from stellar_sdk import Network
    from stellar_sdk import Server
    from stellar_sdk import TransactionBuilder
    from stellar_sdk.exceptions import BaseHorizonError
    
    server = Server(horizon_url="https://horizon.stellar.org")
    network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE
    
    issuing_keypair = Keypair.from_secret("SB........")
    issuing_public = issuing_keypair.public_key
    
    issuing_account = server.load_account(issuing_public)
    
    transaction = (
        TransactionBuilder(
            source_account=issuing_account,
            network_passphrase=network_passphrase,
            base_fee=100,
        )
        .append_set_options_op(
            home_domain="www.ludi.coach"  # Replace with your domain.
        )
        .build()
    )
    transaction.sign(issuing_keypair)
    try:
        transaction_resp = server.submit_transaction(transaction)
        print(f"Transaction Resp:\n{transaction_resp}")
    except BaseHorizonError as e:
        print(f"Error: {e}")
    

The Stellar network will automatically look for the hosted toml file under your domain, and update the information on the mainnet. Note that there is a difference between ludi.coach and www.ludi.coach! Make sure to use the correct domain in your case.

If you want to aidrop your custom Stellar tokens to other people, you can create claimable balances. Many wallets like Lobstr support claiming them. Run the following code:

import time
from stellar_sdk.xdr import TransactionResult, OperationType
from stellar_sdk.exceptions import NotFoundError, BadResponseError, BadRequestError
from stellar_sdk import (
    Keypair,
    Network,
    Server,
    TransactionBuilder,
    Transaction,
    Asset,
    Operation,
    Claimant,
    ClaimPredicate,
    CreateClaimableBalance,
    ClaimClaimableBalance
)

server = Server("https://horizon.stellar.org")
ludi_token = Asset("ludi", "GB4ZKHJTG7O6AUBPVTIDTMVDWWUVWZAOLX5HEOHBCRYSNWB4CWEERTBY")
A = Keypair.from_secret("SB........")
aAccount = server.load_account(A.public_key)

def create_claimable_balance(B, amount, timeout=60 * 60 * 24 * 7):
    B = Keypair.from_public_key(B)
    passphrase = Network.PUBLIC_NETWORK_PASSPHRASE

    # Create a claimable balance with our two above-described conditions.
    soon = int(time.time() + timeout)
    bCanClaim = ClaimPredicate.predicate_before_relative_time(timeout)
    aCanClaim = ClaimPredicate.predicate_not(
        ClaimPredicate.predicate_before_absolute_time(soon)
    )

    # Create the operation and submit it in a transaction.
    claimableBalanceEntry = CreateClaimableBalance(
        asset=ludi_token,  # If you wanted to aidrop Stellar Lumens: Asset.native()
        amount=str(amount),
        claimants=[
            Claimant(destination=B.public_key, predicate=bCanClaim),
            Claimant(destination=A.public_key, predicate=aCanClaim)
        ]
    )

    tx = (
        TransactionBuilder (
            source_account=aAccount,
            network_passphrase=passphrase,
            base_fee=server.fetch_base_fee()
        )
        .append_operation(claimableBalanceEntry)
        .set_timeout(180)
        .build()
    )

    tx.sign(A)
    try:
        txResponse = server.submit_transaction(tx)
        print("Claimable balance created!")
        return "ok"
    except (BadRequestError, BadResponseError) as err:
        print(f"Tx submission failed: {err}")
        return err

Note that it would also be possible to create the above transactions using the Stellar laboratory. I opted for the code for more control. Each transaction costs 100 stroops (0.00001 Stellar Lumens)

Now, the last step is getting listed on some exchanges. But this is for another post.

Published on