Source Code

;; @contract Trading
;; @version 0.1
;; @description Atomic position management across DeFi protocols

(use-trait borrow-helper .test-zest-borrow-helper-trait-v2.zest-borrow-helper-trait)
(use-trait staking 'SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.staking-trait-v1.staking-trait)
(use-trait staking-silo 'SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.staking-silo-trait-v1.staking-silo-trait)
(use-trait hbtc-vault .test-vault-trait-v2.vault-trait)

(use-trait ft 'SP2VCQJGH7PHP2DJK7Z0V48AGBHQAW3R3ZW1QF4N.ft-trait.ft-trait)
(use-trait ft-mint 'SP2VCQJGH7PHP2DJK7Z0V48AGBHQAW3R3ZW1QF4N.ft-mint-trait.ft-mint-trait)
(use-trait oracle 'SP2VCQJGH7PHP2DJK7Z0V48AGBHQAW3R3ZW1QF4N.oracle-trait.oracle-trait)
(use-trait redeemable-token 'SP2VCQJGH7PHP2DJK7Z0V48AGBHQAW3R3ZW1QF4N.redeemeable-trait-v1-2.redeemeable-trait)
(use-trait incentives 'SP2VCQJGH7PHP2DJK7Z0V48AGBHQAW3R3ZW1QF4N.incentives-trait-v2-1.incentives-trait)

;;-------------------------------------
;; Constants
;;-------------------------------------

(define-constant ERR_INVALID_AMOUNT (err u120001))
(define-constant ERR_EMPTY_CLAIM_IDS (err u120002))

(define-constant zest-interface .test-zest-interface-hbtc-v4)

;;-------------------------------------
;; Open Zest Position
;;-------------------------------------

;; @desc - Borrows USDh from Zest and stakes it in Hermetica
;; @param - borrow-helper-trait: Zest borrow helper contract
;; @param - staking-trait: Hermetica staking contract
;; @param - lp-usdh-trait: Zest USDh LP token
;; @param - oracle-trait: Oracle for price feeds
;; @param - borrowed-asset-trait: Asset to borrow (e.g., USDh token contract)
;; @param - usdh-borrow-amount: Amount of USDh to borrow
;; @param - interest-rate-mode: 0 for stable rate, 1 for variable rate
;; @param - pool-reserve-data: Zest pool reserve data contract
;; @param - fee-calculator: Zest fee calculator contract
;; @param - pools: List of Zest pool assets for collateral calculations
;; @param - price-feed-1: Optional price feed update for oracle
;; @param - price-feed-2: Optional second price feed update
(define-public (zest-open
  (borrow-helper-trait <borrow-helper>) (staking-trait <staking>) 
  (lp-usdh-trait <ft>) (oracle-trait <oracle>) (borrowed-asset-trait <ft>)
  (usdh-borrow-amount uint) (interest-rate-mode uint)
  (pool-reserve-data principal) (fee-calculator principal)
  (pools (list 100 { asset: <ft>, lp-token: <ft-mint>, oracle: <oracle> }))
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .test-hq-vaults-v4 check-is-trader contract-caller))
    (asserts! (> usdh-borrow-amount u0) ERR_INVALID_AMOUNT)
    ;; Borrow asset using the supplied collateral
    ;; The borrowed asset will be transferred to Reserve by zest-interface
    (try! (contract-call? .test-zest-interface-hbtc-v4 zest-borrow
      borrow-helper-trait pool-reserve-data oracle-trait borrowed-asset-trait lp-usdh-trait
      pools usdh-borrow-amount fee-calculator interest-rate-mode
      price-feed-1 price-feed-2))

    ;; Stake the borrowed USDh into Hermetica to earn sUSDh yield
    ;; The hermetica-interface will move USDh from Reserve and return sUSDh to Reserve
    (try! (contract-call? .test-hermetica-interface-hbtc-v4 hermetica-stake usdh-borrow-amount staking-trait))

    (print { action: "zest-open", user: contract-caller, data: { usdh-borrowed: usdh-borrow-amount, interest-rate-mode: interest-rate-mode } })
    (ok true)
  )
)

;; @desc - Opens a leveraged position: supplies sBTC to Zest, borrows USDh, stakes USDh in Hermetica
;; @param - borrow-helper-trait: Zest borrow helper contract
;; @param - staking-trait: Hermetica staking contract
;; @param - lp-sbtc-trait: Zest sBTC LP token
;; @param - lp-usdh-trait: Zest USDh LP token
;; @param - oracle-trait: Oracle for price feeds
;; @param - incentives-trait: Zest incentives contract
;; @param - sbtc-token-trait: sBTC token contract
;; @param - borrowed-asset-trait: Asset to borrow (e.g., USDh token contract)
;; @param - sbtc-supply-amount: Amount of sBTC to supply as collateral
;; @param - usdh-borrow-amount: Amount of USDh to borrow
;; @param - interest-rate-mode: 0 for stable rate, 1 for variable rate
;; @param - pool-reserve-data: Zest pool reserve data contract
;; @param - fee-calculator: Zest fee calculator contract
;; @param - pools: List of Zest pool assets for collateral calculations
;; @param - referral: Optional referral address for Zest
;; @param - price-feed-1: Optional price feed update for oracle
;; @param - price-feed-2: Optional second price feed update
(define-public (zest-open-add
  (borrow-helper-trait <borrow-helper>) (staking-trait <staking>)
  (lp-sbtc-trait <redeemable-token>) (lp-usdh-trait <ft>) (oracle-trait <oracle>) (incentives-trait <incentives>)
  (sbtc-token-trait <ft>) (borrowed-asset-trait <ft>)
  (sbtc-supply-amount uint) (usdh-borrow-amount uint) (interest-rate-mode uint)
  (pool-reserve-data principal) (fee-calculator principal)
  (pools (list 100 { asset: <ft>, lp-token: <ft-mint>, oracle: <oracle> }))
  (referral (optional principal))
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .test-hq-vaults-v4 check-is-trader contract-caller))
    (asserts! (> sbtc-supply-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (> usdh-borrow-amount u0) ERR_INVALID_AMOUNT)

    ;; Step 1: Supply sBTC to Zest as collateral
    (try! (contract-call? .test-zest-interface-hbtc-v4 zest-supply
      borrow-helper-trait lp-sbtc-trait pool-reserve-data sbtc-token-trait
      sbtc-supply-amount referral incentives-trait))

    ;; Step 2: Borrow USDh and stake it in Hermetica
    (try! (zest-open
      borrow-helper-trait staking-trait lp-usdh-trait oracle-trait borrowed-asset-trait
      usdh-borrow-amount interest-rate-mode
      pool-reserve-data fee-calculator pools
      price-feed-1 price-feed-2))

    (print { action: "zest-open-add", user: contract-caller, data: { sbtc-supplied: sbtc-supply-amount, usdh-borrowed-and-staked: usdh-borrow-amount, interest-rate-mode: interest-rate-mode } })
    (ok true)
  )
)

;;-------------------------------------
;; Close Zest Position
;;-------------------------------------

;; @desc - Unstakes sUSDh from Hermetica and repays USDh to Zest
;; @param - borrow-helper-trait: Zest borrow helper contract
;; @param - staking-trait: Hermetica staking contract
;; @param - staking-silo-trait: Hermetica silo for withdrawal claims
;; @param - borrowed-asset-trait: Asset to repay (e.g., USDh token contract)
;; @param - susdh-unstake-amount: Amount of sUSDh to unstake from Hermetica
;; @param - usdh-repay-amount: Amount of USDh to repay to Zest (can be partial)
(define-public (zest-close
  (borrow-helper-trait <borrow-helper>) (staking-trait <staking>) (staking-silo-trait <staking-silo>) 
  (borrowed-asset-trait <ft>)
  (susdh-unstake-amount uint) (usdh-repay-amount uint))
  (begin
    (try! (contract-call? .test-hq-vaults-v4 check-is-trader contract-caller))
    (asserts! (> susdh-unstake-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (> usdh-repay-amount u0) ERR_INVALID_AMOUNT)
    (let (
      ;; Unstake sUSDh from Hermetica (instant withdrawal)
      (usdh-amount (try! (contract-call? .test-hermetica-interface-hbtc-v4 hermetica-unstake-and-withdraw susdh-unstake-amount staking-trait staking-silo-trait))))
      ;; Repay USDh loan to Zest
      ;; The zest-interface will move borrowed asset from Reserve to Zest
      (try! (contract-call? .test-zest-interface-hbtc-v4 zest-repay borrow-helper-trait borrowed-asset-trait usdh-repay-amount zest-interface))
      (print { action: "zest-close", user: contract-caller, data: { susdh-unstaked: susdh-unstake-amount, usdh-received: usdh-amount, usdh-repaid: usdh-repay-amount } })
      (ok true)
    )
  )
)

;; @desc - Withdraws sBTC collateral from Zest and funds withdrawal claims
;; @param - borrow-helper-trait: Zest borrow helper contract
;; @param - hbtc-vault-trait: Vault for sBTC collateral claims
;; @param - lp-sbtc-trait: Zest sBTC LP token
;; @param - sbtc-token-trait: sBTC token contract
;; @param - oracle-trait: Oracle for price feeds
;; @param - incentives-trait: Zest incentives contract
;; @param - collateral-amount: Amount of sBTC collateral to withdraw
;; @param - claim-ids: List of claim IDs to fund with sBTC (must have at least one)
;; @param - pool-reserve-data: Zest pool reserve data contract
;; @param - assets: List of Zest pool assets for collateral calculations
;; @param - price-feed-1: Optional price feed update for oracle
;; @param - price-feed-2: Optional second price feed update
(define-public (zest-withdraw-fund
  (borrow-helper-trait <borrow-helper>) (hbtc-vault-trait <hbtc-vault>)
  (lp-sbtc-trait <redeemable-token>) (sbtc-token-trait <ft>) (oracle-trait <oracle>) (incentives-trait <incentives>)
  (collateral-amount uint) 
  (claim-ids (list 1000 uint))
  (pool-reserve-data principal)
  (assets (list 100 { asset: <ft>, lp-token: <ft-mint>, oracle: <oracle> }))
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .test-hq-vaults-v4 check-is-trader contract-caller))
    (asserts! (> collateral-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (> (len claim-ids) u0) ERR_EMPTY_CLAIM_IDS)
    (try! (contract-call? .test-hq-vaults-v4 check-is-protocol (contract-of hbtc-vault-trait)))

    ;; Step 1: Withdraw sBTC collateral from Zest
    (try! (contract-call? .test-zest-interface-hbtc-v4 zest-withdraw
      borrow-helper-trait lp-sbtc-trait pool-reserve-data sbtc-token-trait oracle-trait
      collateral-amount assets incentives-trait
      price-feed-1 price-feed-2))

    ;; Step 2: Fund claims with withdrawn sBTC
    (try! (contract-call? hbtc-vault-trait fund-claim-many claim-ids))

    (print { action: "zest-withdraw-fund-claims", user: contract-caller, data: { collateral-amount: collateral-amount, claim-ids: claim-ids } })
    (ok true)
  )
)

Functions (4)

FunctionAccessArgs
zest-openpublicborrow-helper-trait: <borrow-helper>, staking-trait: <staking>, lp-usdh-trait: <ft>, oracle-trait: <oracle>, borrowed-asset-trait: <ft>, usdh-borrow-amount: uint, interest-rate-mode: uint, pool-reserve-data: principal, fee-calculator: principal, pools: (list 100 { asset: <ft>, lp-token: <ft-mint>, oracle: <oracle> }
zest-open-addpublicborrow-helper-trait: <borrow-helper>, staking-trait: <staking>, lp-sbtc-trait: <redeemable-token>, lp-usdh-trait: <ft>, oracle-trait: <oracle>, incentives-trait: <incentives>, sbtc-token-trait: <ft>, borrowed-asset-trait: <ft>, sbtc-supply-amount: uint, usdh-borrow-amount: uint, interest-rate-mode: uint, pool-reserve-data: principal, fee-calculator: principal, pools: (list 100 { asset: <ft>, lp-token: <ft-mint>, oracle: <oracle> }
zest-closepublicborrow-helper-trait: <borrow-helper>, staking-trait: <staking>, staking-silo-trait: <staking-silo>, borrowed-asset-trait: <ft>, susdh-unstake-amount: uint, usdh-repay-amount: uint
zest-withdraw-fundpublicborrow-helper-trait: <borrow-helper>, hbtc-vault-trait: <hbtc-vault>, lp-sbtc-trait: <redeemable-token>, sbtc-token-trait: <ft>, oracle-trait: <oracle>, incentives-trait: <incentives>, collateral-amount: uint, claim-ids: (list 1000 uint