Welsh Street Liquidity System
The Welsh Street Exchange implements a unique five-tier liquidity system that addresses different needs within the WELSH economy. Understanding the distinctions between these functions is crucial for grasping how the protocol transforms idle WELSH into productive DeFi infrastructure.
The contract owner has exclusive access to initial-liquidity, which is used only during deployment to establish the pool ratio. Once the pool is initialized, anyone can use provide-liquidity to add tradeable liquidity positions or lock-liquidity to create permanent base liquidity. All LP token holders can use remove-liquidity and burn-liquidity to manage their positions at any time.
Liquidity Functions
Burn Liquidity
The burn-liquidity function allows LP token holders to permanently destroy their CREDIT tokens without withdrawing the underlying liquidity. This reduces the total LP token supply while leaving the pool reserves unchanged, which increases the value of all remaining LP tokens. Burned tokens do not count toward the locked liquidity tracking variables, making this distinct from locked liquidity that accumulates from withdrawal taxes and direct deposits into the liquidity pool. Users forfeit their pool claims entirely, which increases the proportional value for remaining LP holders.
;; burn-liquidity
(define-public (burn-liquidity (amount uint))
(begin
(asserts! (> amount u0) ERR_ZERO_AMOUNT)
;; transfer CREDIT from tx-sender to street-market contract
(try! (contract-call? .credit-token transfer amount tx-sender .street-market none))
;; decreases the user's rewards claim
(try! (contract-call? .street-rewards decrease-rewards tx-sender amount))
;; only street-market can call the credit-token burn function
(try! (as-contract? ((with-ft .credit-token "credit" amount))
(try! (contract-call? .credit-token burn amount))))
(ok {
amount-lp: amount,
})
)
)Lock Liquidity
The lock-liquidity function creates permanently committed base liquidity that cannot be withdrawn by anyone. When called, tokens are transferred to the exchange contract and the locked-a and locked-b variables are updated for tracking purposes, but no actual LP tokens are minted to any address. This liquidity becomes protocol-owned infrastructure that supports all trading operations.
;; lock-liquidity
(define-public (lock-liquidity (amount-a uint))
(let (
;; locked liquidity tracked by contract
(lock-a (var-get locked-a))
(lock-b (var-get locked-b))
;; total liquidity (reserves) tracked by contract
(res-a (var-get reserve-a))
(res-b (var-get reserve-b))
)
(begin
(asserts! (> amount-a u0) ERR_ZERO_AMOUNT)
(asserts! (and (> res-a u0) (> res-b u0)) ERR_NOT_INITIALIZED)
;; calculates amount-b based on existing reserves ratio
(let ((amount-b (/ (* amount-a res-b) res-a)))
(begin
(asserts! (> amount-b u0) ERR_ZERO_AMOUNT)
;; directly transfers assets to liquidity pool. No LP tokens minted.
(try! (contract-call? .welshcorgicoin transfer amount-a tx-sender .street-market none))
(try! (contract-call? .street-token transfer amount-b tx-sender .street-market none))
;; updates reserves and locked internal tracking variables
(var-set locked-a (+ lock-a amount-a))
(var-set locked-b (+ lock-b amount-b))
(var-set reserve-a (+ res-a amount-a))
(var-set reserve-b (+ res-b amount-b))
(ok {
amount-a: amount-a,
amount-b: amount-b
})
)
)
)
)
)Initial Liquidity
The initial-liquidity function allows the contract owner to set the pool ratio based on actual market conditions at deployment rather than using hardcoded values. This function only works when the pool is completely empty and takes two independent inputs for amount-a (WELSH) and amount-b (STREET), enabling proper price discovery based on real market data. The contract owner receives LP tokens calculated using the geometric mean of both amounts, which represents standard AMM behavior.
(define-public (initial-liquidity (amount-a uint) (amount-b uint))
(let (
;; locked liquidity tracked by contract
(lock-a (var-get locked-a))
(lock-b (var-get locked-b))
;; total liquidity (reserves) tracked by contract
(res-a (var-get reserve-a))
(res-b (var-get reserve-b))
;; used for initialization check
(total-lp (unwrap-panic (contract-call? .credit-token get-total-supply)))
;; sets the initial liquidity pool ration based on geometric mean
(amount-lp (sqrti (* amount-a amount-b)))
)
(begin
(asserts! (> amount-a u0) ERR_ZERO_AMOUNT)
(asserts! (> amount-b u0) ERR_ZERO_AMOUNT)
;; only admin or owner can set initial liquidity ratio
(asserts! (is-eq tx-sender (var-get contract-owner)) ERR_NOT_CONTRACT_OWNER)
;; initialization check
(asserts! (or
(and (is-eq res-a u0) (is-eq res-b u0))
(is-eq total-lp u0))
ERR_INITIALIZED)
;; transfers assets from user to liquidity pool
(try! (contract-call? .welshcorgicoin transfer amount-a tx-sender .street-market none))
(try! (contract-call? .street-token transfer amount-b tx-sender .street-market none))
;; mints LP tokens to user
(try! (contract-call? .credit-token mint amount-lp))
;; updates user's reward accounting. deployer must be part of reward accounting
(try! (contract-call? .street-rewards increase-rewards tx-sender amount-lp))
;; increases reserves and also tracks locked liquidity
(var-set reserve-a (+ lock-a amount-a))
(var-set reserve-b (+ lock-b amount-b))
(ok {
amount-a: amount-a,
amount-b: amount-b,
amount-lp: amount-lp
})
)
)
)Provide Liquidity
The provide-liquidity function enables normal AMM liquidity provision with LP token issuance. Users specify an amount-a (WELSH) input and the contract calculates the required amount-b (STREET) based on the existing available liquidity ratio, not the total reserves. The function mints CREDIT tokens to the user proportional to their contribution and updates the reserve-a and reserve-b variables. These LP tokens represent pool ownership and can be redeemed through remove-liquidity, subject to a withdrawal tax.
(define-public (provide-liquidity (amount-a uint))
(let (
;; locked liquidity tracked by contract
(lock-a (var-get locked-a))
(lock-b (var-get locked-b))
;; total liquidity (reserves) tracked by contract
(res-a (var-get reserve-a))
(res-b (var-get reserve-b))
;; available liquidity calculated as the invariant of reserve and locked liquidity
(avail-a (if (>= res-a lock-a) (- res-a lock-a) u0))
(avail-b (if (>= res-b lock-b) (- res-b lock-b) u0))
;; fetch total-liquidity for ratio calculations
(total-lp (unwrap-panic (contract-call? .credit-token get-total-supply)))
)
(begin
(asserts! (> amount-a u0) ERR_ZERO_AMOUNT)
(asserts! (> total-lp u0) ERR_NOT_INITIALIZED)
(asserts! (and (> avail-a u0) (> avail-b u0)) ERR_NOT_INITIALIZED)
;; liquidity provisions based on available liquidity
(let (
;; calculate amount-b based on pool ratio
(amount-b (/ (* amount-a avail-b) avail-a))
;; hypothetical LP tokens if token-a alone determined the mint
(lp-from-a (/ (* amount-a total-lp) avail-a))
;; hypothetical LP tokens if token-b alone determined the mint
(lp-from-b (/ (* amount-b total-lp) avail-b))
;; LP minted is the smaller of the two calcs above to ensure LP shares
;; never over-represent what was deposited
(amount-lp (if (< lp-from-a lp-from-b) lp-from-a lp-from-b))
)
(begin
;; user transfer token-a to liquidity pool
(try! (contract-call? .welshcorgicoin transfer amount-a tx-sender .street-market none))
;; user transfer token-b to liquidity pool
(try! (contract-call? .street-token transfer amount-b tx-sender .street-market none))
;; lp-tokens minted to user based on available liquidity calculations
(try! (contract-call? .credit-token mint amount-lp))
;; user rewards tracking updated
(try! (contract-call? .street-rewards increase-rewards tx-sender amount-lp))
;; amounts of token-a and token-b updated in the total reserves
(var-set reserve-a (+ res-a amount-a))
(var-set reserve-b (+ res-b amount-b))
(ok {
amount-a: amount-a,
amount-b: amount-b,
amount-lp: amount-lp
})
)
)
)
)
)Remove Liquidity
The remove-liquidity function allows LP token holders to withdraw their liquidity position at any time without lock-up periods. Users can remove any amount of their LP tokens, receiving their proportional share of available reserves minus a withdrawal tax. The tax percentage is applied to both tokens and these taxed amounts are permanently added to locked-a and locked-b, increasing the protocol-owned liquidity base. Users receive the net amount after tax and their LP tokens are burned. The function also recalculates the user’s distribution tracking based on their new LP balance.
(define-public (remove-liquidity (amount-lp uint))
(let (
;; locked liquidity tracked by contract
(lock-a (var-get locked-a))
(lock-b (var-get locked-b))
;; total liquidity (reserves) tracked by contract
(res-a (var-get reserve-a))
(res-b (var-get reserve-b))
;; available liquidity calculated as reserve minus locked
(avail-a (if (>= res-a lock-a) (- res-a lock-a) u0))
(avail-b (if (>= res-b lock-b) (- res-b lock-b) u0))
;; fetch total-liquidity for proportional withdrawal
(total-lp (unwrap-panic (contract-call? .credit-token get-total-supply)))
)
(begin
;; cannot remove zero and pool must be initialized
(asserts! (> amount-lp u0) ERR_ZERO_AMOUNT)
(asserts! (> total-lp u0) ERR_NOT_INITIALIZED)
(let (
;; gross WELSH portion user is entitled to from available pool
(remove-a (/ (* amount-lp avail-a) total-lp))
;; gross STREET portion user is entitled to from available pool
(remove-b (/ (* amount-lp avail-b) total-lp))
;; withdrawal tax on WELSH
(tax-a (/ (* remove-a TAX) BASIS))
;; withdrawal tax on STREET
(tax-b (/ (* remove-b TAX) BASIS))
;; net amounts sent back to user after tax
(amount-a (- remove-a tax-a))
(amount-b (- remove-b tax-b))
)
(begin
;; LP tokens returned from user to pool contract
(try! (contract-call? .credit-token transfer amount-lp tx-sender .street-market none))
;; send net WELSH back to user
(try! (transformer .welshcorgicoin amount-a tx-sender))
;; send net STREET back to user
(try! (transformer .street-token amount-b tx-sender))
;; update user's reward accounting for decreased LP balance
(try! (contract-call? .street-rewards decrease-rewards tx-sender amount-lp))
;; burn the returned LP tokens
(try! (as-contract? ((with-ft .credit-token "credit" amount-lp))
(try! (contract-call? .credit-token burn amount-lp))))
;; update total reserves to reflect withdrawn net amounts
(var-set reserve-a (if (>= res-a amount-a) (- res-a amount-a) u0))
(var-set reserve-b (if (>= res-b amount-b) (- res-b amount-b) u0))
;; add tax amounts to permanently locked liquidity
(var-set locked-a (+ lock-a tax-a))
(var-set locked-b (+ lock-b tax-b))
(ok {
amount-a: amount-a,
amount-b: amount-b,
amount-lp: amount-lp,
tax-a: tax-a,
tax-b: tax-b
})
)
)
)
)
)Remove Liquidity Tax
The exit tax on liquidity removal using remove-liquidity permanently increases protocol locked liquidity reserves. The exit tax is applied uniformly to all withdrawal transactions. The tax amount remains as permanently locked liquidity within the protocol.
A 1% withdrawal tax is retained in the pool and permanently added to reserves, increasing the invariant (k) and deepening liquidity. This functions as an exit-side stabilization mechanism.
The tax amount is set at contract deployment and immutable.
Locked Liquidity
Historically in DeFi, “locked liquidity” has often been narrative rather than math: if a contract only tracks total reserves, there’s no strict on-chain line between what can move and what cannot. Welsh Street instead treats locked liquidity as a hard invariant by tracking locked-a/locked-b separately from reserve-a/reserve-b, and by basing all LP mint/burn operations on available liquidity only (avail = reserves - locked). Because the locked portion never enters the withdrawal math, it is structurally excluded from user exits, giving the pool a clear, verifiable base layer of liquidity that is transparent and enforceable directly on-chain.
Building on this foundation, the Welsh Street Exchange adds two complementary liquidity functions that give users operational flexibility without weakening that locked base. Users may burn liquidity by calling burn-liquidity, which destroys CREDIT tokens permanently, or directly lock liquidity by calling lock-liquidity, which deposits WELSH and STREET into the pool and updates the locked counters tracked on-chain. The differences between burn-liquidity and lock-liquidity are detailed below.
Burn Liquidity vs Lock Liquidity
The two liquidity functions burn-liquidity and lock-liquidity offer two very distinct liquidity functions. burn-liquidity invokes the burn function in credit-token and destroys the CREDIT tokens. This increases the unit value of all existing CREDIT tokens, and reduces or eliminates a user’s claim to the liquidity pool and rewards. The lock-liquidity function has no interaction with CREDIT tokens as the function directly deposits WELSH and STREET tokens into the liquidity pool, increasing both the reserves and locked liquidity.
The table below compares the lock-liquidity and burn-liquidity functions.
| Aspect | lock-liquidity | burn-liquidity |
|---|---|---|
| Purpose | Protocol-owned base liquidity | Voluntary token destruction |
| User LP Tokens | None issued | Burns existing |
| Locked Counters | Updates locked-a/b | Does not update |
| Remaining LPs | No effect on LP value | Increases LP token value |
| Tracking | Counted as “locked” | Not counted as “locked” |
| Tax Effect | Tax increases locked amounts | Tax doesn’t affect burned tokens |
Locked Liquidity Accounting
All liquidity provisioning via provide-liquidity and remove-liquidity are calculated based on the reserve minus locked invariant referred to as available liquidity or avail. This accounting mechanism makes it impossible to withdraw locked liquidity. Total reserves equal locked plus available liquidity. Available liquidity is what’s actually tradeable and withdrawable by users, while locked liquidity is permanently committed base liquidity that accumulates from taxes and direct deposits. LP tokens represent the total reserves, but locked-lp specifically tracks the locked portion.
;; street market onchain locked liquidity accounting
;; locked liquidity tracked by contract
(define-data-var locked-a uint u0) ;; Locked WELSH
(define-data-var locked-b uint u0) ;; Locked STREET
;; total liquidity reserves tracked by contract
(define-data-var reserve-a uint u0) ;; Total WELSH in contract
(define-data-var reserve-b uint u0) ;; Total STREET in contract
;; reserves = locked + availableLocked liquidity accumulates from taxes collected on remove-liquidity withdrawals and direct deposits to the liquidity pool by utilizing lock-liquidity. Protocol-owned liquidity ensures the exchange always has trading depth as tax collection strengthens the permanent liquidity foundation.