SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.age000-governance-token
Audited: 2026-02-25 · Clarity version: pre-Clarity 4 · Confidence: High
AGE000 Governance Token is the core governance token contract for the ALEX DEX ExecutorDAO system — the largest decentralized exchange on Stacks. It implements SIP-010 fungible token traits alongside a DAO-governed extension interface for minting, burning, locking, and transferring tokens.
Source: On-chain (Hiro Explorer) · Hiro API
Architecture: The contract defines two fungible tokens: alex (transferable) and alex-locked (non-transferable locked variant). Access control is dual-layered: the ExecutorDAO and its extensions can call privileged edg-* functions, while a separate approved-contracts map grants mint/burn access to specific contracts. Standard SIP-010 transfer is available to token holders. A fixed-point math layer (8-decimal precision) wraps core operations for protocol-level convenience.
| Metric | Score | Weight | Weighted |
|---|---|---|---|
| Financial risk | 3 | 3 | 9 |
| Deployment likelihood | 3 | 2 | 6 |
| Code complexity | 2 | 2 | 4 |
| User exposure | 3 | 1.5 | 4.5 |
| Novelty | 2 | 1.5 | 3 |
| Raw Score | 2.65 | ||
| Clarity version penalty (pre-Clarity 4) | -0.50 | ||
| Final Score | 2.15 ✓ | ||
Description: The edg-burn function accepts an arbitrary owner parameter and burns tokens from their account. It only verifies the caller is the DAO or an approved contract — it does not check that the owner consented. Any approved contract or DAO extension can burn tokens from any holder.
(define-public (edg-burn (amount uint) (owner principal))
(begin
(asserts! (or (is-ok (is-dao-or-extension)) (is-ok (check-is-approved))) err-unauthorised)
(ft-burn? alex amount owner)
)
)
Impact: A compromised or malicious approved contract could burn tokens from arbitrary users. While this is gated behind DAO governance, the lack of owner consent is a trust assumption that should be explicit.
Recommendation: This is by design for DAO governance tokens (the DAO needs slashing/burning capability). However, consider adding an explicit sender-is-owner check on the public burn wrapper, while keeping the DAO-only edg-burn unrestricted. Alternatively, document this trust assumption prominently.
Description: The edg-transfer function transfers tokens from sender to recipient with only DAO/extension authorization — it does not verify the sender consented to the transfer.
(define-public (edg-transfer (amount uint) (sender principal) (recipient principal))
(begin
(try! (is-dao-or-extension))
(ft-transfer? alex amount sender recipient)
)
)
Impact: Any DAO extension can unilaterally move tokens from one user to another. This is a powerful privilege that extends beyond normal token operations. Combined with the DAO's ability to add extensions dynamically, a malicious proposal could drain any holder's tokens.
Recommendation: By design for DAO governance, but this is one of the most sensitive functions in the contract. In a Clarity 4 migration, as-contract? with with-ft allowances would provide language-level constraints on which tokens can be moved.
Description: The contract provides edg-add-approved-contract to add entries to the approved-contracts map (setting them to true), but there is no corresponding removal function. Once a contract is approved, it remains approved forever unless the governance token contract itself is replaced.
(define-public (edg-add-approved-contract (new-approved-contract principal))
(begin
(try! (is-dao-or-extension))
(ok (map-set approved-contracts new-approved-contract true))
)
)
Impact: If an approved contract is found to have a vulnerability, it cannot be deauthorized. Approved contracts can mint and burn tokens (including burning from arbitrary owners per M-01). The only mitigation would be to deploy a new governance token contract entirely.
Recommendation: Add a edg-remove-approved-contract function (or generalize to edg-set-approved-contract taking a bool). This would allow the DAO to revoke privileges without redeploying.
Description: The alex token is defined without a max supply parameter: (define-fungible-token alex). This means there is no protocol-level cap on minting — supply is bounded only by the uint max value.
Impact: The DAO (or any approved contract) can mint unlimited tokens. While governance controls minting, there is no safety net against hyperinflation through a malicious proposal.
Recommendation: Consider defining a max supply: (define-fungible-token alex u1000000000000000). This provides a hard ceiling that even governance cannot override.
Description: The set-decimals function allows the DAO to change the token's decimal count post-deployment. This also affects the fixed-point math layer since pow-decimals uses the mutable value.
(define-public (set-decimals (new-decimals uint))
(begin
(try! (is-dao-or-extension))
(ok (var-set token-decimals new-decimals))
)
)
Impact: Changing decimals after deployment would break all DEX integrations, wallet displays, and the fixed-point conversion functions (fixed-to-decimals, decimals-to-fixed). If decimals were changed to 0, pow-decimals would return 1 and the fixed-point layer would produce wildly incorrect values.
Recommendation: Make decimals immutable: (define-constant token-decimals u8). Mutable name/symbol/URI are acceptable (rebranding), but decimals should never change.
Description: The helper edg-mint-many-iter calls ft-mint? directly (not wrapped in try!), and the outer function uses map which collects results. If any individual mint fails (e.g., to an invalid principal or due to supply cap), the error is silently included in the result list rather than aborting the whole batch.
(define-private (edg-mint-many-iter (item {amount: uint, recipient: principal}))
(ft-mint? alex (get amount item) (get recipient item))
)
(define-public (edg-mint-many (recipients (list 200 {amount: uint, recipient: principal})))
(begin
(try! (is-dao-or-extension))
(ok (map edg-mint-many-iter recipients))
)
)
Impact: A batch mint that partially fails could go unnoticed by the calling proposal. The caller receives (ok (list ...)) containing a mix of (ok true) and (err ...) values with no aggregate failure signal.
Recommendation: Use fold with error propagation instead of map, or have the iterator use unwrap-panic to abort on any failure.
Description: This contract was deployed before Clarity 4 was available and does not use the new as-contract? safety builtins. While this contract doesn't use as-contract (it doesn't hold assets), a Clarity 4 migration would benefit the broader ExecutorDAO system that interacts with this token.
Recommendation: When upgrading the DAO system, consider migrating to Clarity 4 with explicit asset allowances on any contracts that call edg-transfer or edg-mint.
Description: Four contracts are hardcoded as approved at deploy time:
(map-set approved-contracts .alex-reserve-pool true)
(map-set approved-contracts .exchange true)
(map-set approved-contracts .faucet true)
(map-set approved-contracts tx-sender true)
Notably, tx-sender (the deployer) is given permanent mint/burn approval, and a .faucet contract is included.
Impact: The deployer retains mint/burn privileges independent of the DAO. If the deployer key is compromised, tokens can be minted freely. Combined with M-03 (no removal mechanism), this approval cannot be revoked.
Description: The SIP-010 get-balance function returns the sum of both alex and alex-locked balances. This means the reported balance includes non-transferable locked tokens.
(define-read-only (get-balance (who principal))
(ok (+ (ft-get-balance alex who) (ft-get-balance alex-locked who)))
)
Impact: Integrations relying on get-balance to determine transferable tokens will overestimate. The separate edg-get-locked function exists for locked balance queries, but standard SIP-010 consumers won't know to use it.
tx-sender or contract-caller equals sender — proper owner authorization.alex-locked fungible token for locking is elegant — locked tokens can't be transferred via standard SIP-010, and total supply remains consistent.ONE_8 conversion functions provide safe protocol-level precision handling, avoiding rounding errors in callers.callback function allows the DAO to activate this as an extension cleanly.edg-set-approved-contract function with a bool parameter would solve this.tx-sender approval (I-02) means the deployer retains mint/burn power permanently. Evaluate whether this is still needed.