(use-trait sip010-trait .trait-sip-010.sip-010-trait)
(define-constant err-unauthorised (err u1000))
(define-constant err-paused (err u1001))
(define-constant err-peg-in-address-not-found (err u1002))
(define-constant err-request-not-found (err u1003))
(define-constant err-token-not-found (err u1004))
(define-constant err-invalid-amount (err u1005))
(define-constant err-token-mismatch (err u1006))
(define-constant err-invalid-tx (err u1007))
(define-constant err-already-sent (err u1008))
(define-constant err-address-mismatch (err u1009))
(define-constant err-request-already-revoked (err u1010))
(define-constant err-request-already-finalized (err u1011))
(define-constant err-revoke-grace-period (err u1012))
(define-constant err-invalid-input (err u1013))
(define-constant MAX_UINT u340282366920938463463374607431768211455)
(define-constant ONE_8 u100000000)
(define-constant gas-fee-token .token-susdt)
(define-data-var contract-owner principal tx-sender)
(define-data-var fee-address principal tx-sender)
(define-public (set-contract-owner (new-contract-owner principal))
(begin
(try! (is-contract-owner))
(ok (var-set contract-owner new-contract-owner))))
(define-public (set-fee-address (new-fee-address principal))
(begin
(try! (is-contract-owner))
(ok (var-set fee-address new-fee-address))))
(define-read-only (get-request-revoke-grace-period)
(contract-call? .brc20-bridge-registry-dev-preview-1 get-request-revoke-grace-period)
)
(define-read-only (is-peg-in-address-approved (address (buff 128)))
(contract-call? .brc20-bridge-registry-dev-preview-1 is-peg-in-address-approved address))
(define-read-only (get-token-to-tick-or-fail (token principal))
(contract-call? .brc20-bridge-registry-dev-preview-1 get-token-to-tick-or-fail token))
(define-read-only (get-token-details-or-fail (tick (string-utf8 4)))
(contract-call? .brc20-bridge-registry-dev-preview-1 get-token-details-or-fail tick))
(define-read-only (get-token-details-or-fail-by-address (token principal))
(contract-call? .brc20-bridge-registry-dev-preview-1 get-token-details-or-fail-by-address token))
(define-read-only (is-approved-token (tick (string-utf8 4)))
(contract-call? .brc20-bridge-registry-dev-preview-1 is-approved-token tick))
(define-read-only (get-request-or-fail (request-id uint))
(contract-call? .brc20-bridge-registry-dev-preview-1 get-request-or-fail request-id))
(define-read-only (create-order-or-fail (order principal))
(contract-call? .brc20-bridge-registry-dev-preview-1 create-order-or-fail order))
(define-read-only (get-peg-in-sent-or-default (bitcoin-tx (buff 4096)) (output uint) (offset uint))
(contract-call? .brc20-bridge-registry-dev-preview-1 get-peg-in-sent-or-default bitcoin-tx output offset))
(define-read-only (get-fee-address)
(var-get fee-address))
(define-public (finalize-peg-in (tx (buff 4096)) (output-index uint) (offset uint) (order-index uint) (token-trait <sip010-trait>))
(let (
(token (contract-of token-trait))
(tx-indexed (try! (contract-call? .indexer-dev-preview-4 get-bitcoin-tx-indexed-or-fail tx output-index offset)))
(parsed-tx (unwrap! (contract-call? .clarity-bitcoin-dev-preview-1 parse-tx tx) err-invalid-tx))
(order-script (get scriptPubKey (unwrap-panic (element-at? (get outs parsed-tx) order-index))))
(order-address (unwrap-panic (from-consensus-buff? principal (unwrap-panic (slice? order-script u2 (len order-script))))))
(token-details (try! (get-token-details-or-fail (get tick tx-indexed))))
(fee (mul-down (get amt tx-indexed) (get peg-in-fee token-details)))
(amt-net (- (get amt tx-indexed) fee)))
(asserts! (not (get peg-in-paused token-details)) err-paused)
(asserts! (is-eq token (get token token-details)) err-token-mismatch)
(asserts! (not (get-peg-in-sent-or-default tx output-index offset)) err-already-sent)
(asserts! (is-peg-in-address-approved (get to tx-indexed)) err-peg-in-address-not-found)
(as-contract (try! (contract-call? .brc20-bridge-registry-dev-preview-1 set-peg-in-sent { tx: tx, output: output-index, offset: offset } true)))
(and (> fee u0) (as-contract (try! (contract-call? token-trait mint-fixed fee (var-get fee-address)))))
(and (> amt-net u0) (as-contract (try! (contract-call? token-trait mint-fixed amt-net order-address))))
(ok (print (merge tx-indexed { type: "peg-in", order-address: order-address, fee: fee, amt-net: amt-net })))))
(define-public (request-peg-out (tick (string-utf8 4)) (amount uint) (peg-out-address (buff 128)) (token-trait <sip010-trait>))
(let (
(token (contract-of token-trait))
(token-details (try! (get-token-details-or-fail tick)))
(fee (mul-down amount (get peg-out-fee token-details)))
(amount-net (- amount fee))
(gas-fee (get peg-out-gas-fee token-details))
(request-details { requested-by: tx-sender, peg-out-address: peg-out-address, tick: tick, amount-net: amount-net, fee: fee, gas-fee: gas-fee, revoked: false, finalized: false, requested-at: block-height })
(request-id (as-contract (try! (contract-call? .brc20-bridge-registry-dev-preview-1 set-request u0 request-details)))))
(asserts! (not (get peg-out-paused token-details)) err-paused)
(asserts! (is-eq token (get token token-details)) err-token-mismatch)
(asserts! (> amount u0) err-invalid-amount)
(try! (contract-call? token-trait transfer-fixed amount tx-sender (as-contract tx-sender) none))
(and (> gas-fee u0) (try! (contract-call? gas-fee-token transfer-fixed gas-fee tx-sender (as-contract tx-sender) none)))
(ok (print (merge request-details { type: "request-peg-out", request-id: request-id })))))
(define-public (finalize-peg-out (request-id uint) (tx (buff 4096)) (output-index uint) (offset uint) (token-trait <sip010-trait>))
(let (
(token (contract-of token-trait))
(request-details (try! (get-request-or-fail request-id)))
(token-details (try! (get-token-details-or-fail (get tick request-details))))
(tx-indexed (try! (contract-call? .indexer-dev-preview-4 get-bitcoin-tx-indexed-or-fail tx output-index offset))) )
(asserts! (not (get peg-out-paused token-details)) err-paused)
(asserts! (is-eq token (get token token-details)) err-token-mismatch)
(asserts! (is-eq (get tick request-details) (get tick tx-indexed)) err-token-mismatch)
(asserts! (is-eq (get amount-net request-details) (get amt tx-indexed)) err-invalid-amount)
(asserts! (is-peg-in-address-approved (get from tx-indexed)) err-peg-in-address-not-found)
(asserts! (is-eq (get peg-out-address request-details) (get to tx-indexed)) err-address-mismatch)
(asserts! (not (get-peg-in-sent-or-default tx output-index offset)) err-already-sent)
(asserts! (not (get revoked request-details)) err-request-already-revoked)
(asserts! (not (get finalized request-details)) err-request-already-finalized)
(as-contract (try! (contract-call? .brc20-bridge-registry-dev-preview-1 set-peg-in-sent { tx: tx, output: output-index, offset: offset } true)))
(as-contract (try! (contract-call? .brc20-bridge-registry-dev-preview-1 set-request request-id (merge request-details { finalized: true }))))
(and (> (get fee request-details) u0) (as-contract (try! (contract-call? token-trait transfer-fixed (get fee request-details) tx-sender (var-get fee-address) none))))
(and (> (get gas-fee request-details) u0) (as-contract (try! (contract-call? gas-fee-token transfer-fixed (get gas-fee request-details) tx-sender (var-get fee-address) none))))
(as-contract (try! (contract-call? token-trait burn-fixed (get amount-net request-details) tx-sender)))
(ok (print { type: "finalize-peg-out", request-id: request-id, tx: tx }))))
(define-public (revoke-peg-out (request-id uint) (token-trait <sip010-trait>))
(let (
(token (contract-of token-trait))
(request-details (try! (get-request-or-fail request-id)))
(token-details (try! (get-token-details-or-fail (get tick request-details)))))
(asserts! (not (get peg-out-paused token-details)) err-paused)
(asserts! (is-eq token (get token token-details)) err-token-mismatch)
(asserts! (> block-height (+ (get requested-at request-details) (get-request-revoke-grace-period))) err-revoke-grace-period)
(asserts! (not (get revoked request-details)) err-request-already-revoked)
(asserts! (not (get finalized request-details)) err-request-already-finalized)
(as-contract (try! (contract-call? .brc20-bridge-registry-dev-preview-1 set-request request-id (merge request-details { revoked: true }))))
(and (> (get fee request-details) u0) (as-contract (try! (contract-call? token-trait transfer-fixed (get fee request-details) tx-sender (get requested-by request-details) none))))
(and (> (get gas-fee request-details) u0) (as-contract (try! (contract-call? gas-fee-token transfer-fixed (get gas-fee request-details) tx-sender (get requested-by request-details) none))))
(as-contract (try! (contract-call? token-trait transfer-fixed (get amount-net request-details) tx-sender (get requested-by request-details) none)))
(ok (print { type: "revoke-peg-out", request-id: request-id }))))
(define-private (is-contract-owner)
(ok (asserts! (is-eq (var-get contract-owner) tx-sender) err-unauthorised)))
(define-private (min (a uint) (b uint))
(if (< a b) a b))
(define-private (mul-down (a uint) (b uint))
(/ (* a b) ONE_8))
(define-private (div-down (a uint) (b uint))
(if (is-eq a u0)
u0
(/ (* a ONE_8) b)))