;; title: market-marker
;; version:
;; summary:
;; description:
;; traits
;; Cryptoeconomic Primitive Smart Contract
;; This contract implements various cryptoeconomic primitives for DeFi applications
;; Error codes
(define-constant ERR-NOT-AUTHORIZED (err u100))
(define-constant ERR-INSUFFICIENT-BALANCE (err u101))
(define-constant ERR-INVALID-PARAMETER (err u102))
(define-constant ERR-POOL-DEPLETED (err u103))
(define-constant ERR-OWNER-ONLY (err u104))
(define-constant ERR-NOT-ACTIVE (err u105))
(define-constant ERR-ALREADY-INITIALIZED (err u106))
(define-constant ERR-EXPIRED (err u107))
(define-constant ERR-INVALID-PRINCIPAL (err u108))
(define-constant ERR-INVALID-TOKEN-ID (err u109))
(define-constant ERR-INVALID-AMOUNT (err u110))
(define-constant ERR-INVALID-WEIGHT (err u111))
(define-constant ERR-INVALID-CURVE-TYPE (err u112))
(define-constant ERR-INVALID-CURVE-PARAMS (err u113))
;; Contract variables
(define-data-var contract-owner principal tx-sender)
(define-data-var protocol-fee-percent uint u5) ;; 0.5% default fee
(define-data-var is-active bool true)
(define-data-var total-liquidity uint u0)
(define-data-var last-price uint u0)
(define-data-var contract-initialized bool false)
;; Asset maps
(define-map user-balances {user: principal, token-id: uint} {amount: uint})
(define-map liquidity-providers principal {amount: uint, last-deposit-block: uint})
(define-map token-pools uint {reserve: uint, weight: uint})
(define-map bonding-curves uint {type: (string-ascii 20), params: (list 5 uint)})
(define-map staking-positions
{user: principal, pool-id: uint}
{amount: uint, rewards: uint, start-block: uint, end-block: uint})
;; Constants
(define-constant PRECISION_FACTOR u1000000) ;; 6 decimal places of precision
(define-constant MIN_LIQUIDITY u1000) ;; Minimum liquidity to start
(define-constant MAX_WEIGHT u1000000) ;; Maximum weight for a token (100%)
(define-constant BLOCKS_PER_YEAR u52560) ;; ~365 days with 10-minute blocks
(define-constant MAX_TOKEN_ID u1000000) ;; Maximum token ID allowed
(define-constant MAX_AMOUNT u1000000000000) ;; Maximum amount allowed (1 trillion)
;; Helper functions
;; Validate principal is not null
(define-private (validate-principal (address principal))
(if (is-eq address tx-sender)
true
(if (is-eq address (var-get contract-owner))
true
(if (is-some (map-get? liquidity-providers address))
true
false))))
;; Validate token ID is within range
(define-private (validate-token-id (token-id uint))
(< token-id MAX_TOKEN_ID))
;; Validate amount is within range
(define-private (validate-amount (amount uint))
(and (> amount u0) (< amount MAX_AMOUNT)))
;; Validate weight is within range
(define-private (validate-weight (weight uint))
(<= weight MAX_WEIGHT))
;; Validate curve type
(define-private (validate-curve-type (curve-type (string-ascii 20)))
(or (is-eq curve-type "linear")
(is-eq curve-type "exponential")
(is-eq curve-type "constant")))
;; Validate curve params
(define-private (validate-curve-params (params (list 5 uint)))
(and (>= (len params) u1) (<= (len params) u5)))
;; Non-recursive power function (supports limited exponents)
(define-private (pow-uint (base uint) (exp uint))
(if (> exp u10)
u0 ;; Return 0 for exponents that are too large
(if (is-eq exp u0)
u1
(if (is-eq exp u1)
base
(if (is-eq exp u2)
(* base base)
(if (is-eq exp u3)
(* base (* base base))
(if (is-eq exp u4)
(* base (* base (* base base)))
(if (is-eq exp u5)
(* base (* base (* base (* base base))))
(if (is-eq exp u6)
(* base (* base (* base (* base (* base base)))))
(if (is-eq exp u7)
(* base (* base (* base (* base (* base (* base base))))))
(if (is-eq exp u8)
(* base (* base (* base (* base (* base (* base (* base base)))))))
(if (is-eq exp u9)
(* base (* base (* base (* base (* base (* base (* base (* base base))))))))
(* base (* base (* base (* base (* base (* base (* base (* base (* base base)))))))))
)
)
)
)
)
)
)
)
)
)
))
;; Read-only functions
;; Get balance for a specific token
(define-read-only (get-balance (user principal) (token-id uint))
(default-to u0 (get amount (map-get? user-balances {user: user, token-id: token-id}))))
;; Check if the caller is the contract owner
(define-read-only (is-owner)
(is-eq tx-sender (var-get contract-owner)))
;; Get token pool information
(define-read-only (get-pool-info (token-id uint))
(map-get? token-pools token-id))
;; Get current protocol fee
(define-read-only (get-protocol-fee)
(var-get protocol-fee-percent))
;; Get contract status
(define-read-only (get-contract-status)
(var-get is-active))
;; Get total liquidity in the contract
(define-read-only (get-total-liquidity)
(var-get total-liquidity))
;; Get liquidity provider information
(define-read-only (get-provider-info (provider principal))
(map-get? liquidity-providers provider))
;; Get bonding curve for a token
(define-read-only (get-bonding-curve (token-id uint))
(map-get? bonding-curves token-id))
;; Get staking position for a user
(define-read-only (get-staking-position (user principal) (pool-id uint))
(map-get? staking-positions {user: user, pool-id: pool-id}))
;; Calculate price using the bonding curve
(define-read-only (calculate-price (token-id uint) (amount uint))
(match (map-get? bonding-curves token-id)
curve
(let (
(curve-type (get type curve))
(curve-params (get params curve))
(current-supply (default-to u0 (get reserve (map-get? token-pools token-id))))
)
(if (is-eq curve-type "linear")
;; Linear: price = m * supply + b
;; params[0] = m (slope), params[1] = b (y-intercept)
(+ (* (default-to u0 (element-at? curve-params u0)) current-supply)
(default-to u0 (element-at? curve-params u1)))
(if (is-eq curve-type "exponential")
;; Exponential: price = a * (b ^ supply)
;; params[0] = a, params[1] = b (scaled by PRECISION_FACTOR)
(let (
(a (default-to u0 (element-at? curve-params u0)))
(b (default-to u0 (element-at? curve-params u1)))
(scaled-exp (/ (* b current-supply) PRECISION_FACTOR))
)
(* a (pow-uint u2 scaled-exp))) ;; Using base 2 with scaled exponent for simplicity
;; Constant: price is fixed
;; params[0] = fixed price
(default-to u0 (element-at? curve-params u0))
)
))
;; Return default value if bonding curve not found
u0
))
;; Calculate rewards for staking
(define-read-only (calculate-staking-rewards (user principal) (pool-id uint))
(match (map-get? staking-positions {user: user, pool-id: pool-id})
position
(let (
(staked-amount (get amount position))
(start-block (get start-block position))
(current-rewards (get rewards position))
(blocks-staked (- stacks-block-height start-block))
(reward-rate (/ (* staked-amount blocks-staked) BLOCKS_PER_YEAR))
)
(+ current-rewards reward-rate))
;; Return 0 if no staking position found
u0
))
;; Calculate weighted price for a swap
(define-read-only (calculate-swap-price (token-in uint) (token-out uint) (amount-in uint))
(match (map-get? token-pools token-in)
pool-in
(match (map-get? token-pools token-out)
pool-out
(let (
(reserve-in (get reserve pool-in))
(reserve-out (get reserve pool-out))
(weight-in (get weight pool-in))
(weight-out (get weight pool-out))
(fee (var-get protocol-fee-percent))
(fee-amount (/ (* amount-in fee) u1000)) ;; fee is in 0.1% units
(amount-in-after-fee (- amount-in fee-amount))
(price-ratio (/ (* reserve-out weight-in) (* reserve-in weight-out)))
)
(/ (* amount-in-after-fee price-ratio) PRECISION_FACTOR))
;; Return 0 if output pool not found
u0
)
;; Return 0 if input pool not found
u0
))
;; Public functions
;; Initialize the contract
(define-public (initialize (owner principal))
(begin
(asserts! (not (var-get contract-initialized)) ERR-ALREADY-INITIALIZED)
;; Validate owner principal
(asserts! (validate-principal owner) ERR-INVALID-PRINCIPAL)
;; Set owner after validation
(var-set contract-owner owner)
(var-set contract-initialized true)
(ok true)))
;; Update contract owner (owner only)
(define-public (set-owner (new-owner principal))
(begin
(asserts! (is-owner) ERR-OWNER-ONLY)
;; Validate new owner principal
(asserts! (validate-principal new-owner) ERR-INVALID-PRINCIPAL)
;; Set new owner after validation
(var-set contract-owner new-owner)
(ok true)))
;; Update protocol fee (owner only)
(define-public (set-protocol-fee (new-fee uint))
(begin
(asserts! (is-owner) ERR-OWNER-ONLY)
;; Fee is in 0.1% units, max 5% (50)
(asserts! (<= new-fee u50) ERR-INVALID-PARAMETER)
(var-set protocol-fee-percent new-fee)
(ok true)))
;; Activate/deactivate contract (owner only)
(define-public (set-contract-status (active bool))
(begin
(asserts! (is-owner) ERR-OWNER-ONLY)
(var-set is-active active)
(ok true)))
;; Create a new token pool
(define-public (create-pool (token-id uint) (initial-reserve uint) (weight uint))
(begin
(asserts! (is-owner) ERR-OWNER-ONLY)
(asserts! (var-get is-active) ERR-NOT-ACTIVE)
;; Validate inputs
(asserts! (validate-token-id token-id) ERR-INVALID-TOKEN-ID)
(asserts! (validate-amount initial-reserve) ERR-INVALID-AMOUNT)
(asserts! (validate-weight weight) ERR-INVALID-WEIGHT)
(asserts! (is-none (map-get? token-pools token-id)) ERR-INVALID-PARAMETER)
;; Create pool with validated inputs
(map-set token-pools token-id {reserve: initial-reserve, weight: weight})
;; Update total liquidity
(var-set total-liquidity (+ (var-get total-liquidity) initial-reserve))
(ok true)))