StacksMint/StacksMintContract · 2 contracts · ~300 lines · February 21, 2026
StacksMint is a two-contract token launchpad for the Stacks blockchain. The token-template.clar is a SIP-010 fungible token that creators fork and deploy. The stacksmint.clar registry is a shared on-chain directory where deployed tokens are listed with metadata (name, symbol, supply, URI).
The core issue: the registry is a trust-me directory with no on-chain verification. Anyone can register any contract principal with arbitrary metadata, enabling impersonation and front-running attacks. The token template itself is a competent SIP-010 implementation with a few design concerns.
| Severity | Count |
|---|---|
| CRITICAL | 1 |
| HIGH | 2 |
| MEDIUM | 3 |
| LOW / INFO | 4 |
Contract: stacksmint.clar · register-token
The register-token function accepts any token-contract principal and arbitrary metadata with zero on-chain verification:
(define-public (register-token
(token-contract principal)
(name (string-ascii 32))
(symbol (string-ascii 10))
(decimals uint)
(total-supply uint)
(token-uri (optional (string-utf8 256))))
(let ((caller tx-sender) ...)
;; No verification that caller deployed token-contract
;; No contract-call? to verify metadata matches
;; owner is set to tx-sender, not the contract's deployer
(map-set token-registry token-contract
{ ... owner: caller ... })))
Attack vectors:
deploy-contract txs, immediately register the new contract principal — the real deployer gets ERR-ALREADY-REGISTEREDThe registry cannot call (contract-call? token-contract get-name) to verify because the token principal is a runtime parameter, not a known contract. This is a fundamental design limitation — the registry architecture cannot provide trustworthy data.
Contract: stacksmint.clar
The README advertises "STX registration fee (anti-spam)" as a feature. The code says otherwise:
;; Registration is free -- no STX fee required (define-constant REGISTRATION-FEE u0)
With zero cost and no verification, an attacker can flood the registry with thousands of fake entries in a single block. The total-fees-collected data var increments by zero — pure dead code. The registry becomes trivially unusable as a discovery tool.
Contract: stacksmint.clar
Since register-token sets the owner field to tx-sender (not the token contract's actual deployer), and registration is free, a front-running attack is trivial:
deploy-contract transactionsregister-token with the victim's contract principalregister-token call fails with ERR-ALREADY-REGISTERED (u200)update-token-uriThere is no admin override, no dispute mechanism, and no deregistration function. The legitimate creator is permanently locked out of their registry entry.
tx-sender Auth Limits ComposabilityContract: token-template.clar · transfer
(asserts! (is-eq tx-sender sender) ERR-NOT-TOKEN-OWNER)
Using tx-sender instead of contract-caller means no smart contract can transfer tokens on behalf of a user. DEXes, vaults, and any intermediary contract calling transfer will fail. This is SIP-010 compliant but breaks DeFi composability. The standard allows either approach — this is the safer but more restrictive choice.
Contract: token-template.clar · burn
(define-public (burn (amount uint) (sender principal))
(begin
(asserts! (is-eq tx-sender sender) ERR-NOT-TOKEN-OWNER)
(asserts! (> amount u0) ERR-INVALID-AMOUNT)
(ft-burn? stacksmint-token amount sender)))
Any holder can burn their own tokens at will. Unlike minting (which has a mintable flag), there is no burnable control. For tokens where supply determines governance weight or economic value, unchecked burning by individual holders can skew distribution. Template users may not realize this is enabled by default.
Contract: token-template.clar · increment / decrement
(define-public (increment)
(begin
(var-set utility-counter (+ (var-get utility-counter) u1))
(ok (var-get utility-counter))))
The counter is a public function with no access control, sharing a single utility-counter across all callers. Anyone can increment/decrement it at any time. If any frontend or integration relies on this value, it's trivially manipulable. This pollutes the contract's ABI with a function that has no practical production use.
(define-constant registry-owner tx-sender) — immutable. No ownership transfer function exists. Currently the owner has no admin functions, but if fee collection or entry management is added later, the owner is permanently fixed to the deploy-time principal.
Same issue in token-template.clar: (define-constant contract-owner tx-sender). If the deployer's key is lost, mint control is permanently inaccessible.
Registry entries are permanent. update-token-uri exists, but name, symbol, decimals, and total-supply are immutable after registration. Typos, malicious registrations, and stale data have no correction path.
When the mintable flag is set to true, the owner can mint unlimited tokens with no maximum supply cap. This is a known trust assumption but should be prominently documented for token holders evaluating the contract.
mintable defaults to false — secure by defaultas-max-len? correctly used for owner-tokens list boundsprint for off-chain indexingThe two-contract architecture (template + registry) is a reasonable approach given Clarity's lack of dynamic contract deployment. However, the registry has a fundamental problem: it cannot verify anything about the contracts it lists. Since the token principal is a runtime parameter, the registry can't call trait functions on it to verify metadata or ownership.
This means the registry is only as trustworthy as its participants — which, on a permissionless blockchain with zero registration cost, means it's not trustworthy at all. A frontend built on this registry would need its own off-chain verification layer, at which point the on-chain registry adds little value.
Verdict: The token template is a solid SIP-010 base suitable for simple tokens. The registry, however, is architecturally unable to fulfill its stated purpose as a trusted token directory.