Source Code

;; 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)))

Functions (24)

FunctionAccessArgs
validate-principalprivateaddress: principal
validate-token-idprivatetoken-id: uint
validate-amountprivateamount: uint
validate-weightprivateweight: uint
validate-curve-typeprivatecurve-type: (string-ascii 20
validate-curve-paramsprivateparams: (list 5 uint
pow-uintprivatebase: uint, exp: uint
get-balanceread-onlyuser: principal, token-id: uint
is-ownerread-only
get-pool-inforead-onlytoken-id: uint
get-protocol-feeread-only
get-contract-statusread-only
get-total-liquidityread-only
get-provider-inforead-onlyprovider: principal
get-bonding-curveread-onlytoken-id: uint
get-staking-positionread-onlyuser: principal, pool-id: uint
calculate-priceread-onlytoken-id: uint, amount: uint
calculate-staking-rewardsread-onlyuser: principal, pool-id: uint
calculate-swap-priceread-onlytoken-in: uint, token-out: uint, amount-in: uint
initializepublicowner: principal
set-ownerpublicnew-owner: principal
set-protocol-feepublicnew-fee: uint
set-contract-statuspublicactive: bool
create-poolpublictoken-id: uint, initial-reserve: uint, weight: uint