LCOV - code coverage report
Current view: top level - contracts/extensions - bme032-0-scalar-strategy-hedge.clar (source / functions) Coverage Total Hit
Test: lcov.info Lines: 0.0 % 104 0
Test Date: 2025-11-05 10:54:00 Functions: 0.0 % 13 0
Branches: 0.0 % 43 0

             Branch data     Line data    Source code
       1                 :             : ;; Title: BME032 Strategy for scalar market hedging
       2                 :             : ;; Synopsis:
       3                 :             : ;; Provides a hook for scalar markets to run hedging function during cool down.
       4                 :             : ;; Description:
       5                 :             : ;; The idea is to create an algorithmic hedge fund - we assume the community 
       6                 :             : ;; surfaces the winning outcome and swap treasury tokens in response. The contractcalls the 
       7                 :             : ;; the treasury with the form/to token contracts and works out the direction bearish/bullish
       8                 :             : ;; of the signal together with the signal strength strong/medium/weak. 
       9                 :             : 
      10                 :             : (impl-trait .hedge-trait.hedge-trait)
      11                 :             : (use-trait ft-velar-token 'SP2AKWJYC7BNY18W1XXKPGP0YVEK63QJG4793Z2D4.sip-010-trait-ft-standard.sip-010-trait)
      12                 :             : 
      13                 :             : (define-constant err-unauthorised (err u32000))
      14                 :             : (define-constant err-already-hedged (err u32001))
      15                 :             : (define-constant err-already-executed (err u32002))
      16                 :             : (define-constant err-hedge-not-found (err u32003))
      17                 :             : (define-constant err-token-incorrect (err u32004))
      18                 :             : (define-constant err-pair-not-found (err u32005))
      19                 :             : (define-constant err-cooldown (err u32006))
      20                 :             : (define-constant err-amount-zero (err u32007))
      21                 :             : (define-constant err-slippage (err u32008))
      22                 :             : (define-constant err-invalid-amount (err u32009))
      23                 :             : 
      24                 :             : (define-constant SCALE u1000000)
      25                 :             : 
      26                 :             : (define-data-var hedge-market-contract principal .bme024-0-market-predicting)
      27                 :             : (define-data-var hedge-scalar-contract principal .bme024-0-market-scalar-pyth)
      28                 :             : (define-data-var hedge-multipliers (list 6 uint) (list u750 u500 u250 u250 u500 u750))
      29                 :             : (define-data-var max-hedge-bips uint u1000)      ;; hard cap per trade = 10% of balance
      30                 :             : (define-data-var max-hedge-abs  uint u0)         ;; optional absolute cap (0 = disabled)
      31                 :             : (define-data-var min-trade      uint u0)         ;; optional minimum trade size (0 = disabled)
      32                 :             : (define-data-var per-market-cooldown uint u144)  ;; ~1 day (tune as needed)
      33                 :             : (define-data-var per-trade-slippage uint u300)   ;; 3% default for hedges (stricter than treasury 5%)
      34                 :             : 
      35                 :             : (define-map last-hedge-height {market-id:uint} uint)  ;; anti-replay
      36                 :             : 
      37                 :             : (define-map swap-token-pairs (buff 32) {token-in: principal, token-out: principal, token0: principal, token1: principal})
      38                 :             : (define-map hedges
      39                 :             :   uint
      40                 :             :   {executed: bool, feed-id: (buff 32)}
      41                 :             : )
      42                 :             : 
      43                 :           0 : (define-public (is-dao-or-extension)
      44    [ - ][ -  - ]:           0 :         (ok (asserts! (or (is-eq tx-sender .bigmarket-dao) (contract-call? .bigmarket-dao is-extension contract-caller)) err-unauthorised)))
      45                 :             : 
      46                 :           0 : (define-public (set-hedge-multipliers (multipliers (list 6 uint)))
      47                 :           0 :   (begin
      48                 :           0 :     (try! (is-dao-or-extension))
      49                 :           0 :     (var-set hedge-multipliers multipliers)
      50                 :           0 :     (print {event: "hedge-multipliers", multipliers: multipliers})
      51                 :           0 :     (ok true)
      52                 :             :   )
      53                 :             : )
      54                 :             : 
      55                 :           0 : (define-public (set-hedge-market-contract (market-contract principal))
      56                 :           0 :   (begin
      57                 :           0 :     (try! (is-dao-or-extension))
      58                 :           0 :     (var-set hedge-market-contract market-contract)
      59                 :           0 :     (print {event: "hedge-market-contract", market-contract: market-contract})
      60                 :           0 :     (ok true)
      61                 :             :   )
      62                 :             : )
      63                 :             : 
      64                 :           0 : (define-public (set-hedge-scalar-contract (market-contract principal))
      65                 :           0 :   (begin
      66                 :           0 :     (try! (is-dao-or-extension))
      67                 :           0 :     (var-set hedge-scalar-contract market-contract)
      68                 :           0 :     (print {event: "hedge-scalar-contract", market-contract: market-contract})
      69                 :           0 :     (ok true)
      70                 :             :   )
      71                 :             : )
      72                 :             : 
      73                 :           0 : (define-public (set-hedge-caps (bips uint) (abs uint))
      74                 :           0 :   (begin (try! (is-dao-or-extension))
      75            [ - ]:           0 :          (asserts! (<= bips u5000) err-invalid-amount) ;; <=50%
      76                 :           0 :          (var-set max-hedge-bips bips)
      77                 :           0 :          (var-set max-hedge-abs  abs)
      78                 :           0 :          (ok true)))
      79                 :             : 
      80                 :           0 : (define-public (set-hedge-min-trade (min uint))
      81                 :           0 :   (begin (try! (is-dao-or-extension)) (var-set min-trade min) (ok true)))
      82                 :             : 
      83                 :           0 : (define-public (set-hedge-cooldown (blocks uint))
      84                 :           0 :   (begin (try! (is-dao-or-extension)) (var-set per-market-cooldown blocks) (ok true)))
      85                 :             : 
      86                 :           0 : (define-public (set-hedge-slippage (bips uint))
      87                 :           0 :   (begin (try! (is-dao-or-extension))
      88    [ - ][ -  - ]:           0 :          (asserts! (and (>= bips u1) (<= bips u3000)) err-invalid-amount)
      89                 :           0 :          (var-set per-trade-slippage bips) (ok true)))
      90                 :             : 
      91                 :           0 : (define-public (set-swap-token-pair
      92                 :             :   (feed-id (buff 32))
      93                 :             :   (token-a principal)
      94                 :             :   (token-b principal)
      95                 :             :   (token-in principal)
      96                 :             :   (token-out principal))
      97                 :           0 :   (begin
      98                 :           0 :     (try! (is-dao-or-extension))
      99                 :             :     ;; Check token-in is one of token-a or token-b
     100    [ - ][ -  - ]:           0 :     (asserts! (or (is-eq token-in token-a) (is-eq token-in token-b)) err-token-incorrect)
     101                 :             :     ;; Check token-out is the other one
     102    [ - ][ -  - ]:           0 :     (asserts! (or (is-eq token-out token-a) (is-eq token-out token-b)) err-token-incorrect)
     103            [ - ]:           0 :     (asserts! (not (is-eq token-in token-out)) err-token-incorrect)
     104                 :             : 
     105                 :             :     ;; Lexicographic ordering
     106                 :           0 :     (let (
     107                 :           0 :       (buff-a (unwrap! (to-consensus-buff? token-a) err-token-incorrect))
     108                 :           0 :       (buff-b (unwrap! (to-consensus-buff? token-b) err-token-incorrect))
     109         [ -  - ]:           0 :       (token0 (if (< buff-a buff-b) token-a token-b))
     110         [ -  - ]:           0 :       (token1 (if (< buff-a buff-b) token-b token-a))
     111                 :             : 
     112                 :             :     )
     113                 :           0 :       (map-set swap-token-pairs
     114                 :           0 :         feed-id
     115                 :             :         {
     116                 :           0 :           token-in: token-in,
     117                 :           0 :           token-out: token-out,
     118                 :           0 :           token0: token0,
     119                 :           0 :           token1: token1
     120                 :             :         })
     121                 :           0 :       (print {event: "swap-token-pair", feed-id: feed-id, token-in: token-in, token-out: token-out, token0: token0, token1: token1})
     122                 :           0 :       (ok true)
     123                 :             :     )
     124                 :             :   )
     125                 :             : )
     126                 :             : 
     127                 :           0 : (define-read-only (get-swap-token-pair (feed-id (buff 32)))
     128                 :           0 :         (map-get? swap-token-pairs feed-id)
     129                 :             : )
     130                 :             : 
     131                 :           0 : (define-public (perform-swap-hedge
     132                 :             :   (market-id uint) (predicted-index uint) (feed-id (buff 32))
     133                 :             :   (token0 <ft-velar-token>) (token1 <ft-velar-token>)
     134                 :             :   (token-in <ft-velar-token>) (token-out <ft-velar-token>)
     135                 :             : )
     136                 :           0 :   (let (
     137                 :           0 :     (pair (unwrap! (map-get? swap-token-pairs feed-id) err-pair-not-found))
     138                 :           0 :     (is-bearish (< predicted-index u3))
     139         [ -  - ]:           0 :     (expected-in  (if is-bearish (get token-in pair)  (get token-out pair)))
     140         [ -  - ]:           0 :     (expected-out (if is-bearish (get token-out pair) (get token-in pair)))
     141                 :           0 :     (lh (default-to u0 (map-get? last-hedge-height {market-id: market-id})))
     142                 :           0 :     (cool (var-get per-market-cooldown))
     143                 :             :   )
     144                 :             :     ;; auth + source contract check
     145                 :           0 :     (try! (is-dao-or-extension))
     146            [ - ]:           0 :     (asserts! (is-eq contract-caller (var-get hedge-scalar-contract)) err-unauthorised)
     147                 :             : 
     148                 :             :     ;; one-shot safety: refuse if this market was already hedged here
     149            [ - ]:           0 :     (asserts! (is-none (map-get? hedges market-id)) err-already-executed)
     150                 :             : 
     151                 :             :     ;; cooldown even if another component tries to hedge repeatedly
     152                 :           0 :     (if (> lh u0)
     153       [ - ][ - ]:           0 :       (asserts! (> stacks-block-height (+ lh cool)) err-cooldown)
     154            [ - ]:           0 :       true
     155                 :             :     )
     156                 :             : 
     157                 :             :     ;; pair validation: enforce tokens match configured direction
     158            [ - ]:           0 :     (asserts! (is-eq (contract-of token-in)  expected-in)  err-token-incorrect)
     159            [ - ]:           0 :     (asserts! (is-eq (contract-of token-out) expected-out) err-token-incorrect)
     160                 :             : 
     161                 :             :     ;; compute bounded amount
     162                 :           0 :     (let (
     163                 :           0 :       (balance (unwrap! (contract-call? token-in get-balance .bme006-0-treasury) err-unauthorised))
     164                 :           0 :       (bips-mult (unwrap! (element-at? (var-get hedge-multipliers) predicted-index) err-token-incorrect)) ;; e.g., 750 = 7.5%
     165                 :           0 :       (cap-bips (var-get max-hedge-bips))
     166         [ -  - ]:           0 :       (bips (if (> bips-mult cap-bips) cap-bips bips-mult))
     167                 :           0 :       (raw-scaled (/ (* (* balance bips) SCALE) u10000))
     168                 :           0 :       (raw (/ raw-scaled SCALE))
     169                 :             : 
     170                 :           0 :       (abs-cap (var-get max-hedge-abs))
     171 [ -  - ][ -  - ]:           0 :       (amt (if (and (> abs-cap u0) (> raw abs-cap)) abs-cap raw))
     172                 :           0 :       (min-size (var-get min-trade))
     173                 :             :     )
     174            [ - ]:           0 :       (asserts! (> amt u0) err-amount-zero)
     175    [ -  - ][ - ]:           0 :       (if (> min-size u0) (asserts! (>= amt min-size) err-amount-zero) true)
     176                 :             : 
     177                 :             :       ;; do the swap with stricter slippage than treasury default
     178                 :           0 :       (let ((slip (var-get per-trade-slippage)))
     179    [ - ][ -  - ]:           0 :         (asserts! (and (>= slip u1) (<= slip u3000)) err-slippage)
     180                 :           0 :         (try! (contract-call? .bme006-0-treasury swap-tokens-with-slippage
     181                 :           0 :               token0 token1 token-in token-out amt slip))
     182                 :             :       )
     183                 :             : 
     184                 :             :       ;; record hedge + height
     185                 :           0 :       (map-set hedges market-id {executed: true, feed-id: feed-id})
     186                 :           0 :       (map-set last-hedge-height {market-id: market-id} stacks-block-height)
     187                 :           0 :       (print {event:"perform-swap-hedge", market-id: market-id, predicted: predicted-index, feed-id: feed-id, amount: amt})
     188                 :           0 :       (ok true)
     189                 :             :     )
     190                 :             :   )
     191                 :             : )
     192                 :             : 
     193                 :             : ;; can be implemented in later contract
     194                 :           0 : (define-public (perform-custom-hedge (market-id uint) (predicted-index uint))
     195                 :           0 :   (begin 
     196                 :             :     ;; caller must be both an ACTIVE extension and sepecifically the scalar prediction market
     197                 :           0 :     (try! (is-dao-or-extension))
     198            [ - ]:           0 :     (asserts! (is-eq contract-caller (var-get hedge-market-contract)) err-unauthorised)
     199                 :           0 :     (print {event: "perform-custom-hedge", market-id: market-id, predicted: predicted-index})
     200                 :           0 :     (ok true)
     201                 :             :   )
     202                 :             : )
     203                 :             : 
     204                 :           0 : (define-private (compute-swap-amount (token <ft-velar-token>) (index uint))
     205                 :           0 :   (let (
     206                 :           0 :       (balance (unwrap! (contract-call? token get-balance .bme006-0-treasury) err-unauthorised))
     207                 :           0 :       (bips (unwrap! (element-at? (var-get hedge-multipliers) index) err-token-incorrect))
     208                 :           0 :       (amt-scaled (/ (* (* balance bips) SCALE) u10000))
     209                 :           0 :       (amt (/ amt-scaled SCALE))
     210                 :             :     )
     211                 :           0 :     (ok amt)
     212                 :             :   )
     213                 :             : )
        

Generated by: LCOV version 2.3.2-1