Source Code

;; SPDX-License-Identifier: BUSL-1.1
;; Copyright (c) 2026 Hermetica Labs, Inc.

;; @contract Trading
;; @version 1
;; @description Batched and atomic position management across DeFi protocols

(use-trait ft 'SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.ft-trait.ft-trait)
(use-trait zest-market 'SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.market-trait.market-trait)
(use-trait zest-vault 'SP1A27KFY4XERQCCRCARCYD1CC5N7M6688BSYADJ7.vault-traits.tokenized-vault)
(use-trait hbtc-vault-trait .vault-trait-v1.vault-trait)
(use-trait staking-trait 'SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.staking-trait-v1.staking-trait)
(use-trait staking-silo-trait 'SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.staking-silo-trait-v1.staking-silo-trait)

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

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

(define-constant usdh-token 'SPN5AKG35QZSK2M8GAMR4AFX45659RJHDW353HSG.usdh-token-v1)

(define-public (zest-open
  (market <zest-market>) (staking <staking-trait>)
  (borrow-token <ft>)
  (borrow-amount uint)
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .hq-v1 check-is-trader contract-caller))
    (asserts! (> borrow-amount u0) ERR_INVALID_AMOUNT)

    (asserts! (is-eq (contract-of borrow-token) usdh-token) ERR_INVALID_TOKEN)

    (try! (contract-call? .zest-interface-hbtc-v1 zest-borrow market borrow-token borrow-amount price-feed-1 price-feed-2))

    (try! (contract-call? .hermetica-interface-hbtc-v1 hermetica-stake borrow-amount staking))
    (print { action: "zest-open", user: contract-caller, data: { market: market, staking: staking, borrow: { token: borrow-token, amount: borrow-amount } } })
    (ok true)
  )
)

(define-public (zest-close
  (market <zest-market>) (staking <staking-trait>) (staking-silo <staking-silo-trait>)
  (repay-token <ft>)
  (unstake-amount uint)
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .hq-v1 check-is-trader contract-caller))
    (asserts! (> unstake-amount u0) ERR_INVALID_AMOUNT)
    (let (

      (repay-amount (try! (contract-call? .hermetica-interface-hbtc-v1 hermetica-unstake-and-withdraw unstake-amount staking staking-silo))))

      (asserts! (is-eq (contract-of repay-token) usdh-token) ERR_INVALID_TOKEN)

      (try! (contract-call? .zest-interface-hbtc-v1 zest-repay market repay-token repay-amount price-feed-1 price-feed-2))

      (print { action: "zest-close", user: contract-caller, data: { market: market, staking: staking, staking-silo: staking-silo, unstake-amount: unstake-amount, repay: { token: repay-token, amount: repay-amount } } })
      (ok true)
    )
  )
)

;;-------------------------------------
;; Open Position - Direct Path
;;-------------------------------------

(define-public (zest-add-open
  (market <zest-market>) (staking <staking-trait>) (collateral-token <ft>) (borrow-token <ft>)
  (collateral-amount uint) (borrow-amount uint)
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .hq-v1 check-is-trader contract-caller))
    (asserts! (> collateral-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (> borrow-amount u0) ERR_INVALID_AMOUNT)

    (try! (contract-call? .zest-interface-hbtc-v1 zest-collateral-add market collateral-token collateral-amount price-feed-1 price-feed-2))

    (asserts! (is-eq (contract-of borrow-token) usdh-token) ERR_INVALID_TOKEN)

    (try! (contract-call? .zest-interface-hbtc-v1 zest-borrow market borrow-token borrow-amount none none))

    (try! (contract-call? .hermetica-interface-hbtc-v1 hermetica-stake borrow-amount staking))

    (print { action: "zest-add-open", user: contract-caller, data: { market: market, staking: staking, collateral: { token: collateral-token, amount: collateral-amount }, borrow: { token: borrow-token, amount: borrow-amount } } })
    (ok true)
  )
)

;;-------------------------------------
;; Close Position - Direct Path
;;-------------------------------------

(define-public (zest-close-remove
  (market <zest-market>) (staking <staking-trait>) (staking-silo <staking-silo-trait>) (hbtc-vault <hbtc-vault-trait>)
  (collateral-token <ft>) (repay-token <ft>)
  (unstake-amount uint) (collateral-amount uint)
  (claim-ids (list 1000 uint))
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .hq-v1 check-is-trader contract-caller))
    (asserts! (> unstake-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (> collateral-amount u0) ERR_INVALID_AMOUNT)

    (let (
      (repay-amount (try! (contract-call? .hermetica-interface-hbtc-v1 hermetica-unstake-and-withdraw unstake-amount staking staking-silo))))

      (asserts! (is-eq (contract-of repay-token) usdh-token) ERR_INVALID_TOKEN)

      (try! (contract-call? .zest-interface-hbtc-v1 zest-repay market repay-token repay-amount price-feed-1 price-feed-2))

      (try! (contract-call? .zest-interface-hbtc-v1 zest-collateral-remove market collateral-token collateral-amount none none))

      (if (> (len claim-ids) u0)
        (begin
          (try! (contract-call? .hq-v1 check-is-protocol (contract-of hbtc-vault)))
          (try! (contract-call? hbtc-vault fund-claim-many claim-ids))
        )
        true)

      (print { action: "zest-close-remove", user: contract-caller, data: { market: market, staking: staking, staking-silo: staking-silo, hbtc-vault: hbtc-vault, collateral: { token: collateral-token, amount: collateral-amount }, unstake-amount: unstake-amount, repay: { token: repay-token, amount: repay-amount }, claim-ids: claim-ids } })
      (ok true)
    )
  )
)

;;-------------------------------------
;; Open Position - Vault Path
;;-------------------------------------

(define-public (zest-deposit-add-open
  (market <zest-market>) (vault <zest-vault>) (staking <staking-trait>)
  (collateral-token <ft>) (borrow-token <ft>)
  (collateral-amount uint) (borrow-amount uint) (min-shares uint)
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .hq-v1 check-is-trader contract-caller))
    (asserts! (> collateral-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (> borrow-amount u0) ERR_INVALID_AMOUNT)

    (try! (contract-call? .zest-interface-hbtc-v1 zest-supply-collateral-add market vault collateral-token collateral-amount min-shares price-feed-1 price-feed-2))

    (asserts! (is-eq (contract-of borrow-token) usdh-token) ERR_INVALID_TOKEN)
    (try! (contract-call? .zest-interface-hbtc-v1 zest-borrow market borrow-token borrow-amount none none))
    (try! (contract-call? .hermetica-interface-hbtc-v1 hermetica-stake borrow-amount staking))

    (print { action: "zest-deposit-add-open", user: contract-caller, data: { market: market, vault: vault, staking: staking, collateral: { token: collateral-token, amount: collateral-amount }, borrow: { token: borrow-token, amount: borrow-amount } } })
    (ok true)
  )
)

;;-------------------------------------
;; Close Position - Vault Path
;;-------------------------------------

(define-public (zest-close-remove-redeem
  (market <zest-market>) (vault <zest-vault>) (staking <staking-trait>) (staking-silo <staking-silo-trait>) (hbtc-vault <hbtc-vault-trait>)
  (repay-token <ft>)
  (unstake-amount uint) (collateral-amount uint) (min-collateral-amount uint)
  (claim-ids (list 1000 uint))
  (price-feed-1 (optional (buff 8192))) (price-feed-2 (optional (buff 8192))))
  (begin
    (try! (contract-call? .hq-v1 check-is-trader contract-caller))
    (asserts! (> unstake-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (> collateral-amount u0) ERR_INVALID_AMOUNT)
    (asserts! (is-eq (contract-of repay-token) usdh-token) ERR_INVALID_TOKEN)

    (let (
      (repay-amount (try! (contract-call? .hermetica-interface-hbtc-v1 hermetica-unstake-and-withdraw unstake-amount staking staking-silo)))
    )
      (try! (contract-call? .zest-interface-hbtc-v1 zest-repay market repay-token repay-amount price-feed-1 price-feed-2))

      (try! (contract-call? .zest-interface-hbtc-v1 zest-collateral-remove-redeem market vault collateral-amount min-collateral-amount none none))

      (if (> (len claim-ids) u0)
        (begin
          (try! (contract-call? .hq-v1 check-is-protocol (contract-of hbtc-vault)))
          (try! (contract-call? hbtc-vault fund-claim-many claim-ids))
        )
        true)

      (print { action: "zest-close-remove-redeem", user: contract-caller, data: { market: market, vault: vault, staking: staking, staking-silo: staking-silo, hbtc-vault: hbtc-vault, collateral: { amount: collateral-amount, min-amount: min-collateral-amount }, unstake-amount: unstake-amount, repay: { token: repay-token, amount: repay-amount }, claim-ids: claim-ids } })
      (ok true)
    )
  )
)

;;-------------------------------------
;; Sweep and Reward
;;-------------------------------------

(define-public (zest-sweep-and-reward
  (asset <ft>)
  (sweep-amount uint)
  (reward uint)
  (is-positive bool))
  (begin
    (try! (contract-call? .hq-v1 check-is-rewarder contract-caller))
    (try! (contract-call? .hq-v1 check-is-trader contract-caller))
    (asserts! (> sweep-amount u0) ERR_INVALID_AMOUNT)

    (try! (contract-call? .zest-interface-hbtc-v1 sweep asset sweep-amount))

    (try! (contract-call? .controller-hbtc-v1 log-reward reward is-positive))

    (print { action: "zest-sweep-and-reward", user: contract-caller, data: { asset: asset, sweep-amount: sweep-amount, reward: reward, is-positive: is-positive } })
    (ok true)
  )
)

Functions (7)

FunctionAccessArgs
zest-openpublicmarket: <zest-market>, staking: <staking-trait>, borrow-token: <ft>, borrow-amount: uint, price-feed-1: (optional (buff 8192
zest-closepublicmarket: <zest-market>, staking: <staking-trait>, staking-silo: <staking-silo-trait>, repay-token: <ft>, unstake-amount: uint, price-feed-1: (optional (buff 8192
zest-add-openpublicmarket: <zest-market>, staking: <staking-trait>, collateral-token: <ft>, borrow-token: <ft>, collateral-amount: uint, borrow-amount: uint, price-feed-1: (optional (buff 8192
zest-close-removepublicmarket: <zest-market>, staking: <staking-trait>, staking-silo: <staking-silo-trait>, hbtc-vault: <hbtc-vault-trait>, collateral-token: <ft>, repay-token: <ft>, unstake-amount: uint, collateral-amount: uint, claim-ids: (list 1000 uint
zest-deposit-add-openpublicmarket: <zest-market>, vault: <zest-vault>, staking: <staking-trait>, collateral-token: <ft>, borrow-token: <ft>, collateral-amount: uint, borrow-amount: uint, min-shares: uint, price-feed-1: (optional (buff 8192
zest-close-remove-redeempublicmarket: <zest-market>, vault: <zest-vault>, staking: <staking-trait>, staking-silo: <staking-silo-trait>, hbtc-vault: <hbtc-vault-trait>, repay-token: <ft>, unstake-amount: uint, collateral-amount: uint, min-collateral-amount: uint, claim-ids: (list 1000 uint
zest-sweep-and-rewardpublicasset: <ft>, sweep-amount: uint, reward: uint, is-positive: bool