17 KiB
self-listing-helper-v3a.clar
The self-listing-helper-v3a contract enables the creation of trading pools on the ALEX DEX through two distinct mechanisms: a permissioned flow and a permissionless flow.
Permissioned
In the permissioned flow, pools can be created with pre-approved tokens by following a guided process through the ALEX UI. Each pool must pair an anchor token (token-x) with a user-provided token (token-y), which is the asset being newly listed (listed token). Both anchor and listed tokens must be approved by the ALEX team.
Permissionless
In the permissionless flow, users can list a new token (token-y) by deploying a wrapper contract that matches an approved template, and without requiring the approval step. The pool is formed against an existing, governance-approved token-x. The contract includes a verification system to ensure the integrity of the deployment: it reconstructs and validates the original contract transaction using Merkle proofs and block data, confirming that the wrapper is trustworthy.
Once verification succeeds, the token is dynamically approved and a pool is created.
Additional Capabilities
The contract also supports:
- Liquidity locking or burning for pool integrity
- On-chain parameter configuration (fees, oracles, thresholds)
- Governance-controlled token approvals
- Rebates management for AMM incentives
This dual approach gives projects the flexibility to choose between a guided listing process or a fully autonomous, on-chain setup — all while using the same core infrastructure.
Features
Public
create
Permissioned pool creation. The listed token (token-y) must be pre-approved to initiate the process.
The function first runs validation checks via pre-check, which ensures the anchor token (token-x) is approved and that the caller provides sufficient liquidity. It also checks that no existing pool with the given token pair and factor already exists.
Next, it verifies that the listing token has a reserve in the amm-vault-v2-01 contract, which serves as a proxy for its approval status.
If all validations pass, the function calls post-check, which:
- Creates the new pool on
amm-pool-v2-01 - Configures its parameters (fees, thresholds, oracle)
- Applies LP token lock or burn rules via
liquidity-lockerif requested
The function emits a print log with the full pool configuration for transparency.
Parameters
| Name | Type |
|---|---|
request-details |
{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) } |
create2
Permissionless pool creation. The pool is created in a single transaction using a wrapper contract that matches an approved template and includes on-chain verification data.
The function begins by validating the request with pre-check. It then calls verify-deploy, which:
- Reconstructs the transaction ID based on the deployment parameters
- Validates that the contract was mined using a Merkle proof and block data
- Ensures the code matches the wrapper template stored in this contract
If verification succeeds, the wrapper is stored in wrap-token-map, and token-y is dynamically approved via amm-vault-v2-01.set-approved-token.
Finally, post-check is executed to create the pool and configure its parameters. The function emits a print log with both the request and verification details.
Parameters
| Name | Type |
|---|---|
request-details |
{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) } |
verify-params |
{ nonce: (buff 8), fee-rate: (buff 8), signature: (buff 65), contract: principal, token-y: principal, proof: { tx-index: uint, hashes: (list 14 (buff 32)), tree-depth: uint }, tx-block-height: uint, block-header-without-signer-signatures: (buff 712) } |
lock-liquidity
This function locks a specified amount of LP tokens for a given pool. It is typically used immediately after a pool is created, when the creator chooses to lock the initial liquidity as a trust signal for other users.
Internally, it calls the lock-liquidity function of the liquidity-locker contract. That contract:
- Transfers the LP tokens from the caller to its own custody
- Records the locked amount and sets an unlock block height (default: ~6 months)
Parameters
| Name | Type |
|---|---|
amount |
uint |
pool-id |
uint |
burn-liquidity
This function allows the caller to burn a specified amount of LP tokens from a given pool. It is one of the options available when configuring the pool after creation, typically used to make the initial liquidity permanently inaccessible.
Internally, it calls the burn-liquidity function of the liquidity-locker contract. That contract:
- Calls the
burn-fixedfunction on the pool contract to destroy the LP tokens - Updates the internal
burnt-liquidityrecord for that pool
Parameters
| Name | Type |
|---|---|
amount |
uint |
pool-id |
uint |
claim-liquidity
This function allows users to reclaim their previously locked LP tokens after the lock period has expired.
Internally, it calls the claim-liquidity function from the liquidity-locker contract. That contract:
- Checks that the caller has a non-zero locked amount
- Verifies that the current block is past the
end-burn-blockset during locking - Transfers the LP tokens back to the user
- Deletes the corresponding lock record
Parameters
| Name | Type |
|---|---|
pool-id |
uint |
Governance Features
is-dao-or-extension
This standard protocol function checks whether a caller (tx-sender) is the DAO executor or an authorized extension, delegating the extensions check to the executor-dao contract.
approve-token-x
A public function, governed through the is-dao-or-extension, that sets the approval status and minimum required balance for a token to be used as the anchor token (token-x) in pool creation.
This function updates the approved-token-x map, enabling the protocol to define which tokens can serve as anchors and to enforce a minimum contribution threshold (min-x) for those tokens.
Parameters
| Name | Type |
|---|---|
token |
principal |
approved |
bool |
min-x |
uint |
set-fee-rebate
A public function, governed through the is-dao-or-extension, that sets the default fee rebate value used during pool creation.
This value is stored locally in the contract and passed as an argument to the set-fee-rebate function of the amm-registry-v2-01 contract when a new pool is initialized.
Parameters
| Name | Type |
|---|---|
new-fee-rebate |
uint |
set-wrapped-token-template
A public function, governed through the is-dao-or-extension, that sets the reference template used to validate wrapper token contracts during permissionless pool creation.
The wrapped-token-template is a list of code segments (as ASCII strings) that represent the expected body of a compliant wrapper contract. When a user submits a deployment proof via create2, this template is used to reconstruct the expected code and verify that the deployed contract matches it exactly.
Parameters
| Name | Type |
|---|---|
new-template |
(list 20 (string-ascii 5000)) |
Getters
get-approved-token-x-or-default
Parameters
| Name | Type |
|---|---|
token-x |
principal |
get-fee-rebate
get-lock-period
get-locked-liquidity-or-default
Parameters
| Name | Type |
|---|---|
owner |
principal |
pool-id |
uint |
get-locked-liquidity-for-pool-or-default
Parameters
| Name | Type |
|---|---|
pool-id |
uint |
get-burnt-liquidity-or-default
Parameters
| Name | Type |
|---|---|
pool-id |
uint |
get-wrapped-token-contract-code
Parameters
| Name | Type |
|---|---|
token |
principal |
Relevant internal functions
pre-check
This private function performs validations prior to pool creation in both permissioned and permissionless flows.
It verifies that:
- The
token-xis approved and has sufficient balance (bal-x). - A pool with the given pair and factor does not already exist (in either order).
- The provided
lockparameter is valid (NONE,LOCK, orBURN).
It retrieves the approval and minimum balance requirements from the internal approved-token-x map and interacts with the amm-pool-v2-01 contract to check pool existence.
Parameters
| Name | Type |
|---|---|
request-details |
{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) } |
post-check
This private function finalizes pool creation by initializing the AMM pool and applying additional configuration parameters.
It performs the following actions:
- Calls the
create-poolfunction from the.amm-pool-v2-01contract to initialize the pool with the provided liquidity amounts. - If the
lockparameter is set toLOCK, it callslock-liquidityfrom theliquidity-lockercontract to lock the initial LP tokens. - If the
lockisBURN, it callsburn-liquidityfrom theliquidity-lockercontract instead. - Applies pool parameters like fee rates, max ratios, thresholds, oracle settings, and the
start-blockby calling their respective setter functions in theamm-pool-v2-01contract. - Finally, it applies the global fee rebate for the pool by calling
set-fee-rebatefrom theamm-registry-v2-01contract.
This function is used after both create and create2 to complete the pool setup.
Parameters
| Name | Type |
|---|---|
request-details |
{ token-x-trait: <ft-trait>, token-y-trait: <ft-trait>, factor: uint, bal-x: uint, bal-y: uint, fee-rate-x: uint, fee-rate-y: uint, max-in-ratio: uint, max-out-ratio: uint, threshold-x: uint, threshold-y: uint, oracle-enabled: bool, oracle-average: uint, start-block: uint, lock: (buff 1) } |
Storage
wrapped-token-template
| Data | Type |
|---|---|
| Variable | list 20 (string-ascii 5000) |
A list of strings that together define the expected code template for a valid wrapper token contract. Each entry represents a fragment of the full contract body, and the full code is reconstructed by concatenating these parts with the listed token's contract address.
This template is used during permissionless pool creation (create2) to verify that a wrapper contract deployed by a user matches the expected safe implementation.
approved-token-x
| Data | Type |
|---|---|
| Map | principal => { approved: bool, min-x: uint } |
A map that stores the approval status and minimum liquidity threshold for tokens used as token-x (anchor token) in pool creation. This validation is applied in both permissioned and permissionless listing flows.
fee-rebate
| Data | Type |
|---|---|
| Variable | uint |
A global rebate value that is assigned to newly created pools. This value is passed to the amm-registry-v2-01 contract during pool setup, where it determines the protocol fee discount applied to the pool.
wrap-token-map
| Data | Type |
|---|---|
| Map | principal => principal |
A map that links a listed token (token-y) to its corresponding verified wrapper contract.
It is only populated during the permissionless listing flow, once the deployment proof is validated.
This allows the AMM system to recognize and route trades through the correct wrapper contract.
Contract calls
executor-dao: calls are made to verify whether a certain contract-caller is designated as an extension.liquidity-locker: this contract is used to manage post-creation liquidity settings. It allows the contract to lock, burn, or later claim LP tokens based on the pool creator’s configuration.clarity-stacks: this contract is used to verify that a token wrapper contract was properly deployed on the Stacks blockchain. It ensures the deployment was mined and included in a valid block.clarity-stacks-helper: this contract is called to convert a Clarity string into its consensus-encoded buffer format.amm-vault-v2-01: this contract is called to verify thattoken-yhas reserves before pool creation and to approve it in the permissionless listing flow after successful wrapper verification.amm-pool-v2-01: this contract is used to validate pool existence, create new trading pools, and configure pool parameters such as fees, slippage thresholds, oracles, and start block.amm-registry-v2-01: this contract is called during pool creation to assign the fee rebate configuration for the newly created pool.
Errors
| Error Name | Value |
|---|---|
err-not-authorised |
(err u1000) |
err-token-not-approved |
(err u1002) |
err-insufficient-balance |
(err u1003) |
err-pool-exists |
(err u1004) |
err-invalid-lock-parameter |
(err u1005) |
err-invalid-length-nonce |
(err u2000) |
err-invalid-length-fee |
(err u2001) |
err-invalid-length-signature |
(err u2002) |
err-invalid-principal-version |
(err u2003) |
err-principal-not-contract |
(err u2004) |