Welsh Street Swaps
Welsh Street implements a constant product Automated Market Maker (AMM) with integrated fee distribution to liquidity providers. The swap functions swap-a-b and swap-b-a enable bidirectional token swapping between WELSH and STREET using the mathematical formula x * y = k, where liquidity is preserved through constant product mechanics. In decentralized finance, this type of AMM is commonly referred to as a Uniswap-V2 Liquidity pool.
Swap Mechanics
The Welsh Street Exchange implements the*constant product formula:
x * y = k
Where:
x= WELSH token reserves (reserve-a)y= STREET token reserves (reserve-b)k= Constant product (maintained across swaps)
In practice this means the trade is always directly against the pooled reserves, not an orderbook: the price quoted get is fully determined by the current pool balances, and larger trades move the price more price impact or slippage.
The swap math is calculated using the total reserves in the liquidity pool. Every trade updates the pool reserves and the locked liquidity so the locked liquidity ratios remain the same as reserves. This is a key mechanism to track locked-liquidity!
Share Fee
The exchange implements a fee system where all swap fees are transferred into the rewards contract and then distributed to liquidity providers, with no protocol revenue retained by the exchange itself. Every unit of trading fee flows back to liquidity providers via the rewards mechanism, so the system has no separate income stream and all fee value ultimately accrues to the LPs.
Swap Functions
(define-public (swap-a-b (amount-a uint))
(let (
;; current locked balances for each side of the pool
(lock-a (var-get locked-a))
(lock-b (var-get locked-b))
;; current pool reserves before the swap
(res-a (var-get reserve-a))
(res-b (var-get reserve-b))
;; fee charged on the incoming WELSH amount
(fee-a (/ (* amount-a FEE) BASIS))
;; user's effective input after subtracting the fee
(amount-a-net (- amount-a fee-a))
;; numerator and denominator for the constant-product pricing formula
(num (* amount-a-net res-b))
(den (+ res-a amount-a-net))
;; STREET output amount implied by the constant-product curve
(amount-b (/ num den))
;; new pool reserves after applying net input and output
(res-a-new (+ res-a amount-a-net))
(res-b-new (- res-b amount-b))
;; rescale locked balances to stay proportional to new reserves
(lock-a-new (if (> res-a u0) (/ (* lock-a res-a-new) res-a) lock-a))
(lock-b-new (if (> res-b u0) (/ (* lock-b res-b-new) res-b) lock-b))
)
(begin
(asserts! (> amount-a u0) ERR_ZERO_AMOUNT)
(asserts! (> amount-b u0) ERR_INVALID_AMOUNT)
(asserts! (and (> res-a u0) (> res-b u0)) ERR_NOT_INITIALIZED)
;; pull input WELSH from user into the market contract
(try! (contract-call? .welshcorgicoin transfer amount-a contract-caller .street-market none))
;; route the WELSH fee portion into the rewards contract
(try! (transformer .welshcorgicoin fee-a .street-rewards))
;; send STREET output tokens to the user
(try! (transformer .street-token amount-b contract-caller))
;; inject the collected WELSH fee into the rewards index for token-a
(try! (contract-call? .street-rewards update-rewards-a fee-a))
;; persist updated pool reserves after the swap
(var-set reserve-a res-a-new)
(var-set reserve-b res-b-new)
;; persist updated locked balances aligned with new reserves
(var-set locked-a lock-a-new)
(var-set locked-b lock-b-new)
(ok {
amount-a: amount-a,
amount-b: amount-b,
fee-a: fee-a,
res-a: res-a,
res-a-new: res-a-new,
res-b: res-b,
res-b-new: res-b-new
})
)
)
)
(define-public (swap-b-a (amount-b uint))
(let (
;; current locked balances for each side of the pool
(lock-a (var-get locked-a))
(lock-b (var-get locked-b))
;; current pool reserves before the swap
(res-a (var-get reserve-a))
(res-b (var-get reserve-b))
;; fee charged on the incoming STREET amount
(fee-b (/ (* amount-b FEE) BASIS))
;; user's effective input after subtracting the fee
(amount-b-net (- amount-b fee-b))
;; numerator and denominator for the constant-product pricing formula
(num (* amount-b-net res-a))
(den (+ res-b amount-b-net))
;; WELSH output amount implied by the constant-product curve
(amount-a (/ num den))
;; new pool reserves after applying net input and output
(res-a-new (- res-a amount-a))
(res-b-new (+ res-b amount-b-net))
;; rescale locked balances to stay proportional to new reserves
(lock-a-new (if (> res-a u0) (/ (* lock-a res-a-new) res-a) lock-a))
(lock-b-new (if (> res-b u0) (/ (* lock-b res-b-new) res-b) lock-b))
)
(begin
(asserts! (> amount-b u0) ERR_ZERO_AMOUNT)
(asserts! (> amount-a u0) ERR_INVALID_AMOUNT)
(asserts! (and (> res-a u0) (> res-b u0)) ERR_NOT_INITIALIZED)
;; pull input STREET from user into the market contract
(try! (contract-call? .street-token transfer amount-b contract-caller .street-market none))
;; route the STREET fee portion into the rewards contract
(try! (transformer .street-token fee-b .street-rewards))
;; send WELSH output tokens to the user
(try! (transformer .welshcorgicoin amount-a contract-caller))
;; inject the collected STREET fee into the rewards index for token-b
(try! (contract-call? .street-rewards update-rewards-b fee-b))
;; persist updated pool reserves after the swap
(var-set reserve-a res-a-new)
(var-set reserve-b res-b-new)
;; persist updated locked balances aligned with new reserves
(var-set locked-a lock-a-new)
(var-set locked-b lock-b-new)
(ok {
amount-a: amount-a,
amount-b: amount-b,
fee-b: fee-b,
res-a: res-a,
res-a-new: res-a-new,
res-b: res-b,
res-b-new: res-b-new
})
)
)
)Price Impact
Price impact is calculated only on the frontend as an informational warning; the on-chain swap contracts do not compute or enforce any price-impact logic. The UI compares the execution price of the trade (output received per unit of input after fees) to the spot price implied by the current reserves, and reports the percentage difference. A higher percentage means the trade is moving the market more (larger slippage).
price impact ≈ 1 − ( execution price / spot price )
The way users control price impact is by setting upper and lower bounds using slippage. The slippage settings let the frontend users chose their tolerance to let the transaction “slip” above or below the price impact displayed on the frontend. If the on-chain outcome exceeds the allowed slippage the transaction fails instead of filling at a worse price than the user expects or can tolerate. Stacks and Clarity contracts achieve this using a user-level security system called post-condition and the mechanics are described in the next section, User Protection.