(use-trait ft-trait .trait-sip-010.sip-010-trait)
(define-constant ERR-NOT-AUTHORIZED (err u1000))
(define-constant ERR-SCHEDULE-NOT-FOUND (err u1001))
(define-constant ERR-PAUSED (err u1002))
(define-constant ERR-UPDATE-CHECKPOINT-FAILED (err u1003))
(define-constant ERR-TOKEN-MISMATCH (err u1004))
(define-constant ERR-VESTING-NOT-STARTED (err u1005))
(define-constant ERR-INVALID-VESTING-DETAILS (err u1006))
(define-constant ERR-UPDATE-VESTING-FAILED (err u1007))
(define-constant ONE_8 u100000000)
(define-constant MAX_UINT u340282366920938463463374607431768211455)
(define-data-var start-height uint MAX_UINT)
(define-data-var end-height uint MAX_UINT)
(define-map vestings principal { stx: uint, alex: uint })
(define-map checkpoints principal uint)
(define-data-var paused bool true)
(define-read-only (is-dao-or-extension)
(ok (asserts! (or (is-eq tx-sender .executor-dao) (contract-call? .executor-dao is-extension contract-caller)) ERR-NOT-AUTHORIZED)))
(define-read-only (get-start-height)
(var-get start-height))
(define-read-only (get-end-height)
(var-get end-height))
(define-read-only (is-paused)
(var-get paused))
(define-read-only (get-vesting-or-fail (participant principal))
(ok (unwrap! (map-get? vestings participant) ERR-SCHEDULE-NOT-FOUND)))
(define-read-only (get-checkpoint-or-fail (participant principal))
(let (
(vesting-details (try! (get-vesting-or-fail participant))))
(match (map-get? checkpoints participant)
some-value (ok some-value)
(ok (get-start-height)))))
(define-read-only (get-stats (participant principal))
(let (
(vesting-details (try! (get-vesting-or-fail participant)))
(vesting-per-block (/ (get alex vesting-details) (- (get-end-height) (get-start-height))))
(checkpoint (try! (get-checkpoint-or-fail participant)))
(new-checkpoint (max (get-start-height) (min (get-end-height) burn-block-height)))
(vested-amount (* (- new-checkpoint checkpoint) vesting-per-block))
(claimed-amount (* (- checkpoint (get-start-height)) vesting-per-block)))
(ok {
available: vested-amount, claimed: claimed-amount, remaining: (- (get alex vesting-details) vested-amount claimed-amount),
checkpoint: checkpoint, new-checkpoint: new-checkpoint })))
(define-public (set-vesting-many (details (list 1000 { participant: principal, details: { stx: uint, alex: uint } })))
(begin
(try! (is-dao-or-extension))
(ok (map set-vesting details))))
(define-public (set-start-height (new-start-height uint))
(begin
(try! (is-dao-or-extension))
(ok (var-set start-height new-start-height))))
(define-public (set-end-height (new-end-height uint))
(begin
(try! (is-dao-or-extension))
(ok (var-set end-height new-end-height))))
(define-public (pause (new-paused bool))
(begin
(try! (is-dao-or-extension))
(ok (var-set paused new-paused))))
(define-public (transfer-fixed (token-trait <ft-trait>) (amount uint) (recipient principal))
(begin
(try! (is-dao-or-extension))
(as-contract (contract-call? token-trait transfer-fixed amount tx-sender recipient none))))
(define-public (claim-stx (participant principal))
(let (
(vesting-details (try! (get-vesting-or-fail participant)))
(updated-details (merge vesting-details { stx: u0 })))
(asserts! (not (is-paused)) ERR-PAUSED)
(asserts! (> burn-block-height (get-start-height)) ERR-VESTING-NOT-STARTED)
(asserts! (map-set vestings participant updated-details) ERR-UPDATE-VESTING-FAILED)
(and (> (get stx vesting-details) u0) (as-contract (try! (contract-call? .token-wstx-v2 transfer-fixed (get stx vesting-details) tx-sender participant none))))
(print { notification: "claim-stx", payload: { participant: participant, claimed: (get stx vesting-details), updated-details: updated-details }})
(ok true)))
(define-public (claim-alex (participant principal))
(let (
(stats (try! (get-stats participant))))
(asserts! (not (is-paused)) ERR-PAUSED)
(asserts! (> burn-block-height (get-start-height)) ERR-VESTING-NOT-STARTED)
(asserts! (map-set checkpoints participant (get new-checkpoint stats)) ERR-UPDATE-CHECKPOINT-FAILED)
(and (> (get available stats) u0) (as-contract (try! (contract-call? .token-alex transfer-fixed (get available stats) tx-sender participant none))))
(print { notification: "claim-alex", payload: { participant: participant, claimed: (get available stats) }, claimed-so-far: (+ (get available stats) (get claimed stats)), remaining: (get remaining stats) })
(ok true)))
(define-public (claim (participant principal))
(begin
(try! (claim-stx participant))
(claim-alex participant)))
(define-public (claim-many (participants (list 1000 principal)))
(ok (map claim participants)))
(define-private (set-vesting (details { participant: principal, details: { stx: uint, alex: uint } }))
(ok (map-set vestings (get participant details) (get details details))))
(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)))
(define-private (min (a uint) (b uint))
(if (<= a b) a b))
(define-private (max (a uint) (b uint))
(if (>= a b) a b))