Source Code

(define-constant err-unauthorized (err u401))
(define-constant err-forbidden (err u403))
(define-constant err-not-found (err u404))
(define-constant err-invalid-amount (err u500))
(define-constant err-no-balance (err u501))
(define-constant max-stacking-amount u1000000000000000)

(define-map admins
  principal
  bool
)
(map-set admins tx-sender true)

(define-data-var last-request-id uint u0)
(define-map withdrawal-requests
  uint
  {
    user: principal,
    amount: uint,
    opens-at: uint,
  }
)
(define-map withdrawal-requests-by-user
  principal
  uint
)

(define-public (deposit (amount uint))
  (begin
    (try! (send-sbtc-to-vault amount))
    (try! (contract-call? .bxl-btc mint amount))
    (ok true)
  )
)

(define-public (withdraw-request
    (amount uint)
    (delay uint)
  )
  (let ((request-id (+ (var-get last-request-id) u1)))
    (asserts! (> amount u0) err-invalid-amount)
    (try! (contract-call? .bxl-btc lock amount))
    (map-set withdrawal-requests request-id {
      user: tx-sender,
      amount: amount,
      opens-at: (+ burn-block-height
        (if (< delay u1000)
          u1000
          delay
        )),
    })
    ;; ensure only one active request per user
    (asserts! (map-insert withdrawal-requests-by-user tx-sender request-id)
      err-forbidden
    )
    (var-set last-request-id request-id)
    (ok request-id)
  )
)

(define-public (withdraw-update
    (request-id uint)
    (amount uint)
    (delay uint)
  )
  (let (
      (details (unwrap! (map-get? withdrawal-requests request-id) err-not-found))
      (user (get user details))
    )
    (asserts! (is-eq user tx-sender) err-unauthorized)
    ;; unlock previous amount for tx-sender
    (try! (contract-call? .bxl-btc unlock (get amount details)))
    (if (is-eq amount u0)
      (begin
        (map-delete withdrawal-requests-by-user user)
        (map-delete withdrawal-requests request-id)
      )
      (begin
        ;; lock new amount for tx-sender
        (try! (contract-call? .bxl-btc lock amount))
        (map-set withdrawal-requests request-id {
          user: tx-sender,
          amount: amount,
          opens-at: (+ burn-block-height
            (if (< delay u1000)
              u1000
              delay
            )),
        })
      )
    )
    (ok request-id)
  )
)

(define-public (withdraw-finalize (request-id uint))
  (let (
      (details (unwrap! (map-get? withdrawal-requests request-id) err-not-found))
      (amount (get amount details))
      (user (get user details))
    )
    (asserts!
      (or
        (is-admin-calling)
        (> burn-block-height (get opens-at details))
      )
      err-unauthorized
    )
    (try! (contract-call? .bxl-btc burn amount user))
    (try! (send-sbtc-from-vault amount user))
    (map-delete withdrawal-requests-by-user user)
    (ok amount)
  )
)

(define-public (deposit-stx (amount uint))
  (begin
    (try! (send-stx-to-vault amount))
    (try! (contract-call? .bxl-stx mint amount))
    (ok true)
  )
)

(define-public (withdraw-stx (amount uint))
  (begin
    (try! (contract-call? .bxl-stx burn amount))
    (try! (send-stx-from-vault amount tx-sender))
    (ok true)
  )
)

(define-public (admin-sbtc-transfer
    (amount uint)
    (recipient principal)
  )
  (let (
      (sbtc-balance (unwrap!
        (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
          get-balance current-contract
        )
        err-no-balance
      ))
      (bxl-btc-supply (unwrap! (contract-call? .bxl-btc get-total-supply) err-no-balance))
    )
    (asserts! (is-admin-calling) err-unauthorized)
    (asserts! (>= sbtc-balance (+ amount bxl-btc-supply)) err-invalid-amount)
    (try! (send-sbtc-from-vault amount recipient))
    (ok true)
  )
)

(define-public (admin-stx-transfer
    (amount uint)
    (recipient principal)
  )
  (let (
      (stx-balance (stx-get-balance current-contract))
      (bxl-stx-supply (unwrap! (contract-call? .bxl-stx get-total-supply) err-no-balance))
    )
    (asserts! (is-admin-calling) err-unauthorized)
    (asserts! (>= stx-balance (+ amount bxl-stx-supply)) err-invalid-amount)
    (try! (send-stx-from-vault amount recipient))
    (ok true)
  )
)

(define-public (admin-set-admin
    (admin principal)
    (enable bool)
  )
  (begin
    (asserts! (is-admin-calling) err-unauthorized)
    (asserts! (not (is-eq admin tx-sender)) err-forbidden)
    (map-set admins admin enable)
    (ok true)
  )
)

;; Dual Stacking

;; sbtc rewards go to this vault
(define-public (enroll)
  (as-contract? ()
    (try! (contract-call? 'SP1HFCRKEJ8BYW4D0E3FAWHFDX8A25PPAA83HWWZ9.dual-stacking-v1
      enroll none
    ))
  )
)

(define-public (delegate-stx)
  (begin
    (asserts! (is-admin-calling) err-unauthorized)
    (as-contract? ((with-stacking max-stacking-amount))
      (try! (contract-call?
        'SPMPMA1V6P430M8C91QS1G9XJ95S59JS1TZFZ4Q4.pox4-multi-pool-v1
        delegate-stx max-stacking-amount
        (unwrap-panic (to-consensus-buff? {
          v: u1,
          c: "sbtc",
          s: "bxl-vault",
        }))
      ))
    )
  )
)

(define-public (revoke-delegate-stx)
  (begin
    (asserts! (is-admin-calling) err-unauthorized)
    (as-contract? ()
      (try! (match (contract-call? 'SP000000000000000000002Q6VF78.pox-4 revoke-delegate-stx)
        success (ok success)
        failure (err (to-uint failure))
      ))
    )
  )
)

;; private functions

(define-private (is-admin-calling)
  (default-to false (map-get? admins tx-sender))
)

(define-private (send-sbtc-to-vault (amount uint))
  (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token transfer
    amount tx-sender current-contract none
  )
)

(define-private (send-sbtc-from-vault
    (amount uint)
    (recipient principal)
  )
  (as-contract?
    ((with-ft 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token "sbtc-token"
      amount
    ))
    (try! (contract-call? 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
      transfer amount tx-sender recipient none
    ))
  )
)

(define-private (send-stx-to-vault (amount uint))
  (stx-transfer? amount tx-sender current-contract)
)

(define-private (send-stx-from-vault
    (amount uint)
    (recipient principal)
  )
  (as-contract? ((with-stx amount))
    (try! (stx-transfer? amount current-contract recipient))
  )
)

;; initialize the bxl-btc and bxl-stx contracts to point to this vault
(try! (contract-call? .bxl-btc set-vault current-contract))
(try! (contract-call? .bxl-stx set-vault current-contract))

;; allow fast pool v2
(try! (as-contract? ()
  (try! (contract-call? 'SP000000000000000000002Q6VF78.pox-4 allow-contract-caller
    'SPMPMA1V6P430M8C91QS1G9XJ95S59JS1TZFZ4Q4.pox4-multi-pool-v1 none
  ))
))

Functions (10)

FunctionAccessArgs
depositpublicamount: uint
withdraw-finalizepublicrequest-id: uint
deposit-stxpublicamount: uint
withdraw-stxpublicamount: uint
enrollpublic
delegate-stxpublic
revoke-delegate-stxpublic
is-admin-callingprivate
send-sbtc-to-vaultprivateamount: uint
send-stx-to-vaultprivateamount: uint