Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE
Need a crash course on Bitcoin layers?
→ READ OUR FREE GUIDE

Building STX.CITY as a Solo Dev on Stacks

Building as a solo dev is no easy task. Building, on top of handling all communications/marketing, makes it even more challenging. Khoa Nguyen, the solo builder behind STX.CITY, has caught the attention of many other builders in the space for his relentless work on the popular memecoin platform. In this interview, Khoa shares his background and experience building with Hiro devtools on Stacks.

Type
Interview
Topic(s)
Ecosystem
Stacks
Published
December 10, 2024
Author(s)
Developer Advocate
Founder, STX.CITY
A blue graphic reading "STX.CITY"
Contents

How did you get involved with Stacks?

My journey with Stacks began during the Blockstack era in 2019. I participated in the AppMining program, which incentivized developers to build decentralized applications using Gaia storage and Blockstack authentication. Along with my colleague, we successfully developed some Dapps that earned us recognition and rewards in the program.

What is the Web3 community like in Vietnam?

Vietnam stands among the global leaders in crypto adoption, with a particularly high penetration rate among Gen Z users, most of whom maintain crypto wallets. While the country has numerous crypto communities, they primarily focus on Ethereum Layer 2 solutions and Solana. 

From a developer standpoint, the landscape is still emerging. Major local projects like Coin98 have prioritized building their user base rather than fostering developer communities. However, this dynamic is shifting, particularly with the Vietnamese government's recent initiative to position blockchain technology as a strategic priority.

What is STX.CITY, and where did the inspiration behind it come from?

STX.CITY is a one-click platform for launching tokens on Stacks. The platform is a comprehensive toolkit for memecoin creators, enabling them to grow their communities through features like AMM listing support (such as on Alex, Velar, and Stackswap), airdrops, token donations, and burn mechanisms.

STX.CITY emerged from my dual passion for no-code solutions and blockchain technology. My goal is to support blockchain development by eliminating coding barriers. The platform has evolved into a Web3 marketplace that bridges the gap between memecoin creators and their communities. 

I chose to build on Stacks after four years of active involvement in its community and maintaining it as my primary investment focus (90% of my portfolio is $STX).

What can one do on STX.City?

One of the powerful reasons for STX.CITY's popularity is that it is no-code. Anyone can create their own memecoin (token) and allow a community to start trading it. Let's unpack that and discuss how creating a token with no code is actually possible. The process takes two parts:

1. Deploying a token.

The bonding token essentially consists of deploying a SIP-010 fungible token. But before the token can be deployed, the memecoin creator needs to fill out a form with the token’s information, such as the token name, ticker, supply, description, logo, social media links, and the target STX amount for the DEX contract. Once the form is correctly filled out, they can then deploy their contract using their connected Stacks wallet.

2. Deploying the DEX contract for that token.

This DEX contract (also coined as the token’s bonding curve DEX) facilitates the initial public trading of the token using STX as its trading pair. By transferring the initial mint of the tokens to this DEX contract, it facilitates a fair launch and alleviates unwanted "ruggable" scenarios. Once it hits a target STX amount, the token will then get listed on a more prominent and established Stacks DEX such as Velar.

What is happening behind the scenes when a token is being created?

STX.CITY handles all the technical implementations such as building the token’s contract code with the given token information supplied by the creator. The token metadata URI, which gets automatically constructed as a JSON file, is hosted and managed on a separate database by STX.CITY. The generated public URI, provided by that database, is then be inserted into the token contract’s <code-rich-text>token-uri<code-rich-text> data variable, which you can see in this example:


(define-data-var token-uri (optional (string-utf8 256)) (some u"https://pdakhjpwkuwtadzmpnjm.supabase.co/storage/v1/object/public/uri/bpjdGmFp-mctrump-fries-0-decimals.json"))

How does the user take this pre-generated contract code of the token and deploy it themselves?

After the SIP-010 Clarity contract code is modified, it is then passed into the <code-rich-text>codeBody<code-rich-text> option of the <code-rich-text>openContractDeploy<code-rich-text> function, which is imported from the <code-rich-text>@stacks/connect<code-rich-text> library. This method allows the user to deploy the modified SIP-010 Clarity contract from their own wallet. The deployer retains full control over their token, including the ability to update token URI and transfer ownership later on.

Here is an example of the deploy function, which invokes their wallet extension to sign and broadcast this as a transaction on the Stacks network:


openContractDeploy({
    contractName: contractName,
    codeBody: modifiedCode, // the SIP-10 token code here
    network: new StacksMainnet(),
    postConditionMode: PostConditionMode.Deny,
    postConditions: [sendSTXPostCondition],
    appDetails: {
        name: 'STX.CITY',
        icon: window.location.origin + '/city.png',
    },
    onFinish: async data => {
        if (data) {
            console.log('Stacks Transaction:', data.stacksTransaction);
            console.log('Transaction ID:', data.txId);
            console.log('Raw transaction:', data.txRaw);
        }
    },
})

After the token contract is created and deployed, the user is then prompted to deploy their DEX contract, which will receive (more on how this works is explained later) all the newly minted tokens from the token contract. Chainhooks are then programmatically created on the Hiro Platform to listen for transaction confirmations. This helps with updating the contract deployment status to the user and the backend.  

After the token and DEX contract are officially deployed and confirmed, how does STX.City display that information on its own token page?

Dynamic rendering of a newly deployed token page consists of querying information from the token’s contract, metadata, and trading information from its DEX contract. 

Once the token contract is confirmed on-chain, Hiro’s Token Metadata API will detect the new token’s metadata and index it for future querying from the fungible token metadata API endpoint: 

https://api.hiro.so/metadata/ft/SP253J64EGMH59TV32CQXXTVKH5TQVGN108TA5TND.fair-bonding-curve

The response from the above endpoint will return the below object:


{
  "tx_id": "0xa2be2a687c716bc05d398156bc245684866dc4d6630d16731f495162f91f4f88",
  "sender_address": "SP253J64EGMH59TV32CQXXTVKH5TQVGN108TA5TND",
  "asset_identifier": "SP253J64EGMH59TV32CQXXTVKH5TQVGN108TA5TND.fair-bonding-curve::FAIR",
  "name": "Fair",
  "symbol": "FAIR",
  "decimals": 6,
  "total_supply": "10000000000000000",
  "token_uri": "https://gaia.hiro.so/hub/1M19CV7cuRSEWzdfxAhiq6KSkDqHEqfoJt/fair-0-decimals.json",
  "description": "FAIR Token is the first community-owned token on the Stacks blockchain, using the STXCITY's bonding curve mechanism. It was introduced through a fair and community-owned launch. Designed to be unruggable, it offers a secure and fair platform for its holders.",
  "image_uri": "https://assets.hiro.so/api/mainnet/token-metadata-api/SP253J64EGMH59TV32CQXXTVKH5TQVGN108TA5TND.fair-bonding-curve/1.png",
  "image_thumbnail_uri": "https://assets.hiro.so/api/mainnet/token-metadata-api/SP253J64EGMH59TV32CQXXTVKH5TQVGN108TA5TND.fair-bonding-curve/1-thumb.png",
  "image_canonical_uri": "https://gaia.hiro.so/hub/1M19CV7cuRSEWzdfxAhiq6KSkDqHEqfoJt/fair-logo.JPG",
  "metadata": {
    "sip": 16,
    "name": "Fair",
    "description": "FAIR Token is the first community-owned token on the Stacks blockchain, using the STXCITY's bonding curve mechanism. It was introduced through a fair and community-owned launch. Designed to be unruggable, it offers a secure and fair platform for its holders.",
    "image": "https://gaia.hiro.so/hub/1M19CV7cuRSEWzdfxAhiq6KSkDqHEqfoJt/fair-logo.JPG",
    "cached_image": "https://assets.hiro.so/api/mainnet/token-metadata-api/SP253J64EGMH59TV32CQXXTVKH5TQVGN108TA5TND.fair-bonding-curve/1.png",
    "cached_thumbnail_image": "https://assets.hiro.so/api/mainnet/token-metadata-api/SP253J64EGMH59TV32CQXXTVKH5TQVGN108TA5TND.fair-bonding-curve/1-thumb.png"
  }
}

With that endpoint, I can then easily display the user’s token image and description across STX.CITY. Other wallets and applications in the ecosystem can also use this endpoint to fetch the token’s metadata.

To give you an idea of how I’ve used Hiro’s devtools to generate a token page on STX.CITY, the above image captures areas on the token’s page where different sets of Hiro APIs are being used to fetch and display data. Here’s a breakdown of the different sets of data fetched from the different API tools:

  • Token Metadata API: For displaying token metadata information
  • Hiro Stacks API: For displaying historical trades and current holders of the token
  • Stacks blockchain API client: For leveraging websockets to listen to real-time updates on buy and sell trades
  • Stacks.js: For the initiation of Buy and Sell trade transactions

How can the user update their own token’s metadata?

The owner of a token can also update their token’s metadata anytime on the app, which will internally invoke their token contract’s set-token-uri function below with a new token metadata URI passed in as an argument:


(define-public (set-token-uri (value (string-utf8 256)))
    (begin
        (asserts! (is-eq tx-sender (var-get contract-owner)) (err ERR-UNAUTHORIZED))
        (var-set token-uri (some value))
        (ok (print {
              notification: "token-metadata-update",
              payload: {
                contract-id: (as-contract tx-sender),
                token-class: "ft"
              }
            })
        )
    )
)

Hiro’s Token Metadata API watches for that specific print event (specifically the notification of  <code-rich-text>token-metadata-update<code-rich-text>) on the network and auto-updates the API’s database to reflect a change in the existing token’s metadata.

What has been the most challenging technical implementation?

I think one big problem devs have with Clarity is that you can't create another contract from a contract. I see most teams have this issue too, and there are different ways to address it. For example, some teams create a lot of pre-defined contracts then select one of them to use.

In the scenario above, where the user needs to deploy both the token and DEX contract, it would be easier to have this done in one transaction rather than in two separate transactions. Since the token contract comes before the deployment of the DEX contract, in most cases there would need to be manual intervention of the creator minting the tokens to the DEX contract, but this defeats the whole purpose of a truly decentralized fair launch.

So to resolve this, there's actually a trick that I use in STX.City: you can send assets to another contract that doesn't exist yet (another fellow Stacks dev, Rozar, taught me that).

Take this token for example. Upon the contract deploy of its token, at the end of the contract code, it’s actually calling the native Clarity function <code-rich-text>ft-mint?<code-rich-text> to mint all of the tokens to the future DEX contract, which is deployed after the token contract itself.


;; Snippet from the .stx-bros-stxcity contract

(begin
    (try! (send-stx 'SP11WRT9TPPKP5492X3VE81CM1T74MD13SPFT527D u1000000))
    (try! (ft-mint? BROS u1000000000000000 'SPMWB0BNTFM19PWTNP0SJ2WX3PW5GTTMBS8BGZ5X.stx-bros-stxcity-dex))
)

This helps streamline the process of making token trading readily available on the DEX contract once it is finally confirmed on the network and alleviates laying the responsibility of a central actor for minting and transferring the tokens to the DEX contract manually. 

What has it been like building as a solo founder/dev, and what advice would you give to other solo builders?

Build small features first, then iterate with user feedback. The sooner you have user feedback, the better because you don’t have resources like a big team. I haven’t experienced any big mishaps myself yet, but my biggest advice is that you should always audit your code if your contract handles user funds.

What’s next for STX.City?

In the near future, STX.City will onboard new users and deploy tokens without requiring a wallet upfront. This would entail generating a Stacks wallet, on behalf of the user, on the backend with the <code-rich-text>@stacks/wallet-sdk<code-rich-text> and then transferring ownership to the user after deployment. This use case will also be leveraging AI Agents in some form, which I am currently working with the aibtcdev team on making this a reality.

Try STX.CITY out for yourself here, and follow us on Twitter.

Product updates & dev resources straight to your inbox
Your Email is in an invalid format
Checkbox is required.
Thanks for
subscribing.
Oops! Something went wrong while submitting the form.
Copy link
Mailbox
Hiro news & product updates straight to your inbox
Only relevant communications. We promise we won’t spam.

Related stories