Source Code

;; title: STXSynAssets
;; version:
;; summary:
;; description:

;; Error code
(define-constant ERROR-NOT-AUTHORIZED (err u100))
(define-constant ERROR-TOKEN-BALANCE-TOO-LOW (err u101))
(define-constant ERROR-INVALID-TOKEN-QUANTITY (err u102))
(define-constant ERROR-ORACLE-DATA-STALE (err u103))
(define-constant ERROR-COLLATERAL-DEPOSIT-INSUFFICIENT (err u104))
(define-constant ERROR-COLLATERAL-BELOW-THRESHOLD (err u105))
(define-constant ERROR-PRICE-OUT-OF-BOUNDS (err u106))
(define-constant ERROR-CALCULATION-OVERFLOW (err u107))
(define-constant ERROR-INVALID-TRANSFER-RECIPIENT (err u108))
(define-constant ERROR-AMOUNT-MUST-BE-POSITIVE (err u109))
(define-constant ERROR-VAULT-NOT-FOUND (err u110))

;; System constants
(define-constant SYSTEM-ADMIN tx-sender)
(define-constant PRICE-VALIDITY-PERIOD-BLOCKS u900) ;; 15 minutes in blocks
(define-constant COLLATERAL-SAFETY-RATIO u150) ;; 150%
(define-constant COLLATERAL-LIQUIDATION-RATIO u120) ;; 120%
(define-constant MIN-TOKEN-ISSUANCE-AMOUNT u100000000) ;; 1.00 tokens (8 decimals)
(define-constant MAX-ALLOWED-PRICE u1000000000000) ;; Price ceiling for safety
(define-constant UINT_MAX u340282366920938463463374607431768211455) ;; 2^128 - 1

;; Contract principal - UPDATE THIS after deployment with actual contract address
;; Example: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stx-collaatx
(define-constant CONTRACT-OWNER tx-sender)

;; System state variables
(define-data-var oracle-update-block-height uint u0)
(define-data-var current-market-price uint u0)
(define-data-var global-token-supply uint u0)

;; Data storage structures
(define-map user-token-holdings principal uint)
(define-map collateralized-positions
    principal
    {
        staked-collateral: uint,
        issued-synthetic-tokens: uint,
        position-open-price: uint
    }
)


;;;; Private Function
;; Internal helper functions
(define-private (process-token-transfer (sender principal) (receiver principal) (transfer-amount uint))
    (let (
        (sender-current-balance (get-user-token-balance sender))
    )
    ;; Safety checks
    (asserts! (> transfer-amount u0) ERROR-AMOUNT-MUST-BE-POSITIVE)
    (asserts! (not (is-eq sender receiver)) ERROR-INVALID-TRANSFER-RECIPIENT)
    (asserts! (>= sender-current-balance transfer-amount) ERROR-TOKEN-BALANCE-TOO-LOW)
    (asserts! (is-some (map-get? user-token-holdings sender)) ERROR-NOT-AUTHORIZED)

    (match (secure-add (get-user-token-balance receiver) transfer-amount)
        receiver-new-balance
            (match (secure-subtract sender-current-balance transfer-amount)
                sender-new-balance
                    (begin
                        (map-set user-token-holdings sender sender-new-balance)
                        (map-set user-token-holdings receiver receiver-new-balance)
                        (ok true))
                error ERROR-CALCULATION-OVERFLOW)
        error ERROR-CALCULATION-OVERFLOW))
)


;; Protected arithmetic operations
(define-private (secure-multiply (value-a uint) (value-b uint))
    (let ((product-result (* value-a value-b)))
        (asserts! (or (is-eq value-a u0) (is-eq (/ product-result value-a) value-b)) ERROR-CALCULATION-OVERFLOW)
        (ok product-result)))

(define-private (secure-add (value-a uint) (value-b uint))
    (let ((sum-result (+ value-a value-b)))
        (asserts! (>= sum-result value-a) ERROR-CALCULATION-OVERFLOW)
        (ok sum-result)))

(define-private (secure-subtract (value-a uint) (value-b uint))
    (begin
        (asserts! (>= value-a value-b) ERROR-CALCULATION-OVERFLOW)
        (ok (- value-a value-b))))

;; Query functions
(define-read-only (get-user-token-balance (account-holder principal))
    (default-to u0 (map-get? user-token-holdings account-holder))
)

(define-read-only (get-circulating-supply)
    (var-get global-token-supply)
)

(define-read-only (get-market-price)
    (var-get current-market-price)
)

(define-read-only (get-position-details (position-owner principal))
    (map-get? collateralized-positions position-owner)
)

(define-read-only (calculate-position-health-ratio (position-owner principal))
    (let (
        (position-data (unwrap! (get-position-details position-owner) (err u0)))
        (latest-price (var-get current-market-price))
    )
    (if (> (get issued-synthetic-tokens position-data) u0)
        (match (secure-multiply (get staked-collateral position-data) u100)
            collateral-value-base (match (secure-multiply collateral-value-base u100)
                collateral-value-adjusted (match (secure-multiply (get issued-synthetic-tokens position-data) latest-price)
                    synthetic-value (ok (/ collateral-value-adjusted synthetic-value))
                    error ERROR-CALCULATION-OVERFLOW)
                error ERROR-CALCULATION-OVERFLOW)
            error ERROR-CALCULATION-OVERFLOW)
        (err u0)))
)


;;; PUBLIC FUNCTIONS ;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Helper function for contract to send STX (Clarity 4 compatible)
(define-private (contract-send-stx (amount uint) (recipient principal))
    (stx-transfer? amount tx-sender recipient)
)

;; External functions
(define-public (set-price-feed-value (new-price uint))
    (begin
        (asserts! (is-eq tx-sender SYSTEM-ADMIN) ERROR-NOT-AUTHORIZED)
        (asserts! (> new-price u0) ERROR-PRICE-OUT-OF-BOUNDS)
        (asserts! (< new-price MAX-ALLOWED-PRICE) ERROR-PRICE-OUT-OF-BOUNDS)
        (var-set current-market-price new-price)
        (var-set oracle-update-block-height stacks-block-height)
        (ok true))
)


(define-public (create-synthetic-tokens (token-amount uint))
    (let (
        (latest-market-price (var-get current-market-price))
    )
    (asserts! (> token-amount u0) ERROR-AMOUNT-MUST-BE-POSITIVE)
    (asserts! (>= token-amount MIN-TOKEN-ISSUANCE-AMOUNT) ERROR-INVALID-TOKEN-QUANTITY)
    (asserts! (<= (- stacks-block-height (var-get oracle-update-block-height)) 
                 PRICE-VALIDITY-PERIOD-BLOCKS) 
              ERROR-ORACLE-DATA-STALE)

    (match (secure-multiply token-amount (/ latest-market-price u100))
        base-collateral-needed 
        (match (secure-multiply base-collateral-needed (/ COLLATERAL-SAFETY-RATIO u100))
            total-collateral-required
            (match (stx-transfer? total-collateral-required tx-sender CONTRACT-OWNER)
                transfer-success
                (begin
                    (map-set collateralized-positions tx-sender
                        {
                            staked-collateral: total-collateral-required,
                            issued-synthetic-tokens: token-amount,
                            position-open-price: latest-market-price
                        })
                    (match (secure-add (get-user-token-balance tx-sender) token-amount)
                        updated-user-balance
                        (begin
                            (map-set user-token-holdings tx-sender updated-user-balance)
                            (match (secure-add (var-get global-token-supply) token-amount)
                                new-total-supply
                                (begin
                                    (var-set global-token-supply new-total-supply)
                                    (ok true))
                                error ERROR-CALCULATION-OVERFLOW))
                        error ERROR-CALCULATION-OVERFLOW))
                error ERROR-COLLATERAL-DEPOSIT-INSUFFICIENT)
            error ERROR-CALCULATION-OVERFLOW)
        error ERROR-CALCULATION-OVERFLOW))
)


(define-public (destroy-synthetic-tokens (token-amount uint))
    (let (
        (position-data (unwrap! (get-position-details tx-sender) 
                              ERROR-VAULT-NOT-FOUND))
        (user-balance (get-user-token-balance tx-sender))
    )
    (asserts! (> token-amount u0) ERROR-AMOUNT-MUST-BE-POSITIVE)
    (asserts! (>= user-balance token-amount) ERROR-TOKEN-BALANCE-TOO-LOW)
    (asserts! (>= (get issued-synthetic-tokens position-data) token-amount) 
              ERROR-NOT-AUTHORIZED)

    (match (secure-multiply (get staked-collateral position-data) token-amount)
        collateral-calculation
        (let (
            (collateral-to-release (/ collateral-calculation 
                                    (get issued-synthetic-tokens position-data)))
        )

        ;; Clarity 4: Removed as-contract. Contract must be authorized to send STX.
        ;; You may need to add authorization logic or use post-conditions.
        (try! (stx-transfer? collateral-to-release CONTRACT-OWNER tx-sender))

        (match (secure-subtract (get staked-collateral position-data) 
                              collateral-to-release)
            remaining-collateral
            (match (secure-subtract (get issued-synthetic-tokens position-data) 
                                   token-amount)
                remaining-tokens
                (begin
                    (map-set collateralized-positions tx-sender
                        {
                            staked-collateral: remaining-collateral,
                            issued-synthetic-tokens: remaining-tokens,
                            position-open-price: (var-get current-market-price)
                        })

                    (match (secure-subtract user-balance token-amount)
                        new-user-balance
                        (begin
                            (map-set user-token-holdings tx-sender new-user-balance)
                            (match (secure-subtract (var-get global-token-supply) 
                                                  token-amount)
                                new-total-supply
                                (begin
                                    (var-set global-token-supply new-total-supply)
                                    (ok true))
                                error ERROR-CALCULATION-OVERFLOW))
                        error ERROR-CALCULATION-OVERFLOW))
                error ERROR-CALCULATION-OVERFLOW)
            error ERROR-CALCULATION-OVERFLOW))
        error ERROR-CALCULATION-OVERFLOW))
)

(define-public (send-synthetic-tokens (recipient principal) (amount uint))
    (begin
        ;; Validation checks
        (asserts! (> amount u0) ERROR-AMOUNT-MUST-BE-POSITIVE)
        (asserts! (<= amount (get-user-token-balance tx-sender)) ERROR-TOKEN-BALANCE-TOO-LOW)
        (asserts! (not (is-eq tx-sender recipient)) ERROR-INVALID-TRANSFER-RECIPIENT)

        ;; Process the transfer after validations
        (process-token-transfer tx-sender recipient amount))
)

(define-public (add-collateral (collateral-amount uint))
    (let (
        (position-data (default-to 
            {
                staked-collateral: u0, 
                issued-synthetic-tokens: u0, 
                position-open-price: u0
            }
            (get-position-details tx-sender)))
    )
    (asserts! (> collateral-amount u0) ERROR-AMOUNT-MUST-BE-POSITIVE)
    (try! (stx-transfer? collateral-amount tx-sender CONTRACT-OWNER))

    (match (secure-add (get staked-collateral position-data) 
                      collateral-amount)
        updated-collateral
        (begin
            (map-set collateralized-positions tx-sender
                {
                    staked-collateral: updated-collateral,
                    issued-synthetic-tokens: (get issued-synthetic-tokens position-data),
                    position-open-price: (var-get current-market-price)
                })
            (ok true))
        error ERROR-CALCULATION-OVERFLOW))
)

(define-public (force-close-position (position-owner principal))
    (let (
        (position-data (unwrap! (get-position-details position-owner) 
                              ERROR-VAULT-NOT-FOUND))
        (health-ratio (unwrap! (calculate-position-health-ratio position-owner) 
                              ERROR-NOT-AUTHORIZED))
    )
    (asserts! (< health-ratio COLLATERAL-LIQUIDATION-RATIO) 
              ERROR-NOT-AUTHORIZED)

    ;; Transfer liquidated collateral to caller
    ;; Clarity 4: Removed as-contract. Contract must be authorized to send STX.
    ;; You may need to add authorization logic or use post-conditions.
    (try! (stx-transfer? (get staked-collateral position-data) CONTRACT-OWNER tx-sender))

    ;; Remove the liquidated position
    (map-delete collateralized-positions position-owner)

    ;; Remove tokens from circulation
    (map-set user-token-holdings position-owner u0)
    (match (secure-subtract (var-get global-token-supply) 
                          (get issued-synthetic-tokens position-data))
        updated-supply
        (begin
            (var-set global-token-supply updated-supply)
            (ok true))
        error ERROR-CALCULATION-OVERFLOW))
)

Functions (16)

FunctionAccessArgs
process-token-transferprivatesender: principal, receiver: principal, transfer-amount: uint
secure-multiplyprivatevalue-a: uint, value-b: uint
secure-addprivatevalue-a: uint, value-b: uint
secure-subtractprivatevalue-a: uint, value-b: uint
get-user-token-balanceread-onlyaccount-holder: principal
get-circulating-supplyread-only
get-market-priceread-only
get-position-detailsread-onlyposition-owner: principal
calculate-position-health-ratioread-onlyposition-owner: principal
contract-send-stxprivateamount: uint, recipient: principal
set-price-feed-valuepublicnew-price: uint
create-synthetic-tokenspublictoken-amount: uint
destroy-synthetic-tokenspublictoken-amount: uint
send-synthetic-tokenspublicrecipient: principal, amount: uint
add-collateralpubliccollateral-amount: uint
force-close-positionpublicposition-owner: principal