;; title: escrow-service
;; version:
;; summary:
;; description:
;; Commodities Trading Contract
;; Implements secure trading of commodities with price feeds, escrow, and trading functionality
;; Error codes
(define-constant ERROR-UNAUTHORIZED-ACCESS (err u100))
(define-constant ERROR-INVALID-COMMODITY-PRICE (err u101))
(define-constant ERROR-INSUFFICIENT-ESCROW-BALANCE (err u102))
(define-constant ERROR-TRADING-DISABLED (err u103))
(define-constant ERROR-INVALID-TRADE-QUANTITY (err u104))
(define-constant ERROR-ESCROW-TRANSACTION-FAILED (err u105))
(define-constant ERROR-INVALID-INPUT (err u106))
;; Data Variables
(define-data-var contract-administrator principal tx-sender)
(define-data-var commodity-price-oracle principal tx-sender)
(define-data-var market-trading-status bool true)
(define-data-var minimum-trade-quantity uint u100)
;; Data Maps
(define-map available-commodities-inventory
{ commodity-identifier: uint }
{
available-quantity: uint,
current-market-price: uint,
commodity-owner: principal
}
)
(define-map active-trading-positions
{ trader-address: principal, trade-position-id: uint }
{
commodity-identifier: uint,
traded-quantity: uint,
position-entry-price: uint,
position-creation-timestamp: uint
}
)
(define-map trader-escrow-accounts
{ trader-address: principal }
{ escrow-balance: uint }
)
;; Read-only functions
(define-read-only (get-commodity-market-data (commodity-identifier uint))
(match (map-get? available-commodities-inventory { commodity-identifier: commodity-identifier })
commodity-market-data (ok commodity-market-data)
(err u404)
)
)
(define-read-only (get-trader-position-details (trader-address principal) (trade-position-id uint))
(match (map-get? active-trading-positions { trader-address: trader-address, trade-position-id: trade-position-id })
trader-position-data (ok trader-position-data)
(err u404)
)
)
(define-read-only (get-trader-escrow-balance (trader-address principal))
(match (map-get? trader-escrow-accounts { trader-address: trader-address })
escrow-account-data (ok (get escrow-balance escrow-account-data))
(err u404)
)
)
;; Private functions
(define-private (verify-administrator-access (caller-address principal))
(if (is-eq caller-address (var-get contract-administrator))
(ok true)
ERROR-UNAUTHORIZED-ACCESS
)
)
(define-private (validate-trade-parameters (trade-quantity uint) (trade-price uint))
(if (and
(>= trade-quantity (var-get minimum-trade-quantity))
(> trade-price u0)
)
(ok true)
ERROR-INVALID-TRADE-QUANTITY
)
)
(define-private (validate-uint (value uint))
(> value u0)
)
;; Public functions
(define-public (update-price-oracle-address (new-oracle-address principal))
(begin
(try! (verify-administrator-access tx-sender))
(asserts! (is-some (some new-oracle-address)) ERROR-INVALID-INPUT)
(ok (var-set commodity-price-oracle new-oracle-address))
)
)
(define-public (toggle-market-trading-status)
(begin
(try! (verify-administrator-access tx-sender))
(ok (var-set market-trading-status (not (var-get market-trading-status))))
)
)
(define-public (register-new-commodity (commodity-identifier uint) (initial-available-quantity uint) (initial-market-price uint))
(begin
(try! (verify-administrator-access tx-sender))
(asserts! (validate-uint commodity-identifier) ERROR-INVALID-INPUT)
(asserts! (validate-uint initial-available-quantity) ERROR-INVALID-INPUT)
(asserts! (validate-uint initial-market-price) ERROR-INVALID-INPUT)
(try! (validate-trade-parameters initial-available-quantity initial-market-price))
(map-set available-commodities-inventory
{ commodity-identifier: commodity-identifier }
{
available-quantity: initial-available-quantity,
current-market-price: initial-market-price,
commodity-owner: tx-sender
}
)
(ok true)
)
)
(define-public (execute-trade (commodity-identifier uint) (trade-quantity uint) (trade-position-id uint))
(let (
(commodity-data (unwrap! (get-commodity-market-data commodity-identifier) ERROR-INVALID-COMMODITY-PRICE))
(current-market-price (get current-market-price commodity-data))
(total-trade-cost (* trade-quantity current-market-price))
)
(begin
(asserts! (var-get market-trading-status) ERROR-TRADING-DISABLED)
(asserts! (validate-uint commodity-identifier) ERROR-INVALID-INPUT)
(asserts! (validate-uint trade-quantity) ERROR-INVALID-INPUT)
(asserts! (validate-uint trade-position-id) ERROR-INVALID-INPUT)
(try! (validate-trade-parameters trade-quantity current-market-price))
;; Check escrow balance
(match (map-get? trader-escrow-accounts { trader-address: tx-sender })
escrow-account-data
(if (>= (get escrow-balance escrow-account-data) total-trade-cost)
(begin
;; Update escrow balance
(map-set trader-escrow-accounts
{ trader-address: tx-sender }
{ escrow-balance: (- (get escrow-balance escrow-account-data) total-trade-cost) }
)
;; Record trading position
(map-set active-trading-positions
{ trader-address: tx-sender, trade-position-id: trade-position-id }
{
commodity-identifier: commodity-identifier,
traded-quantity: trade-quantity,
position-entry-price: current-market-price,
position-creation-timestamp: stacks-block-height
}
)
(ok true)
)
ERROR-INSUFFICIENT-ESCROW-BALANCE
)
ERROR-INSUFFICIENT-ESCROW-BALANCE
)
)
)
)
(define-public (close-trading-position (trade-position-id uint))
(let (
(position-data (unwrap! (get-trader-position-details tx-sender trade-position-id) ERROR-INVALID-TRADE-QUANTITY))
(commodity-data (unwrap! (get-commodity-market-data (get commodity-identifier position-data)) ERROR-INVALID-COMMODITY-PRICE))
(current-market-price (get current-market-price commodity-data))
(position-settlement-amount (* (get traded-quantity position-data) current-market-price))
)
(begin
(asserts! (validate-uint trade-position-id) ERROR-INVALID-INPUT)
;; Return funds to escrow account
(match (map-get? trader-escrow-accounts { trader-address: tx-sender })
escrow-account-data
(map-set trader-escrow-accounts
{ trader-address: tx-sender }
{ escrow-balance: (+ (get escrow-balance escrow-account-data) position-settlement-amount) }
)
(map-set trader-escrow-accounts
{ trader-address: tx-sender }
{ escrow-balance: position-settlement-amount }
)
)
;; Delete the position
(map-delete active-trading-positions { trader-address: tx-sender, trade-position-id: trade-position-id })
(ok true)
)
)
)
;; Contract initialization
(define-public (initialize-contract (administrator-address principal))
(begin
(asserts! (is-some (some administrator-address)) ERROR-INVALID-INPUT)
(var-set contract-administrator administrator-address)
(var-set commodity-price-oracle administrator-address)
(ok true)
)
)