Source Code

;; treasury-grant-v3

(use-trait ft-trait 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.trait-sip-010.sip-010-trait)

(define-constant err-not-authorized (err u1000))
(define-constant err-invalid-amount (err u1001))
(define-constant err-treasury-grant-v2-not-paused (err u1002))
(define-constant err-paused (err u1003))

(define-constant ONE_8 u100000000)
(define-constant total-stx u1328392261866610)
(define-constant multiplier u10)

(define-map claimed uint { stx-claimed: uint, alex-returned: uint })
(define-data-var claim-base uint u0)
(define-data-var paused bool true)

;; read-only calls

(define-read-only (is-dao-or-extension)
  (ok (asserts! (or (is-eq tx-sender 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.executor-dao) (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.executor-dao is-extension contract-caller)) err-not-authorized)))

(define-read-only (get-claim-base)
	(var-get claim-base))

(define-read-only (get-claimed-details-or-default (token-id uint))
	(default-to { stx-claimed: u0, alex-returned: u0 } (map-get? claimed token-id)))

(define-read-only (get-claim-details-or-fail (token-id uint))
	(let (
			(stats (try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 get-stats token-id)))
			(max-stx-claim (- (/ (div-down (mul-down (get-claim-base) (+ (get available stats) (get claimed stats))) total-stx) multiplier) (get stx-claimed (get-claimed-details-or-default token-id)))))
		(ok (merge stats { max-stx-claim: max-stx-claim }))))

(define-read-only (is-paused)
  (var-get paused))

;; governance calls

(define-public (add-to-claim-base (amount uint))
	(begin
		(asserts! (>= total-stx (+ (get-claim-base) amount)) err-invalid-amount)
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2 transfer-fixed amount tx-sender (as-contract tx-sender) none))
		(ok (var-set claim-base (+ (get-claim-base) amount)))))

(define-public (transfer-token (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 (pause (new-paused bool))
  (begin
    (try! (is-dao-or-extension))
    (ok (var-set paused new-paused))))

(define-public (callback (sender principal) (payload (buff 2048)))
	(ok true))

(define-public (execute (sender principal))
	(begin
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.executor-dao set-extensions (list { extension: .treasury-grant-v3, enabled: true } )))
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 pause true))
		(try! (pause false))		
		(ok true)))

;; public calls

(define-public (claim-stx-v2 (token-id uint))
	(begin
		(asserts! (not (is-paused)) err-paused)
		(asserts! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 is-paused) err-treasury-grant-v2-not-paused)	
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 pause false))
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 claim-stx token-id))
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 pause true))
		(ok true)))

(define-public (claim-stx-v3 (token-id uint))
	(let (
			(sender tx-sender)
			(claimed-details (get-claimed-details-or-default token-id))
			(claim-details (try! (get-claim-details-or-fail token-id)))
			(alex-to-return (min (* (get max-stx-claim claim-details) multiplier) (- (get claimed claim-details) (get alex-returned claimed-details))))
			(updated-claimed { stx-claimed: (+ (get stx-claimed claimed-details) (get max-stx-claim claim-details)), alex-returned: (+ (get alex-returned claimed-details) alex-to-return) }))
		(asserts! (not (is-paused)) err-paused)
		(asserts! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 is-paused) err-treasury-grant-v2-not-paused)
		(asserts! (is-eq (some sender) (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 get-owner token-id))) err-not-authorized)

		(map-set claimed token-id updated-claimed)
		(and (> alex-to-return u0) (try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-alex transfer-fixed alex-to-return sender (as-contract tx-sender) none)))
		(as-contract (try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2 transfer-fixed (get max-stx-claim claim-details) tx-sender sender none)))
		
		(print { notification: "claim-stx", payload: { token-id: token-id, owner: sender, claimed: (get max-stx-claim claim-details), returned: alex-to-return } })
		(ok true)))

(define-public (claim-alex (token-id uint))
	(let (
			(sender tx-sender)
			(claimed-details (get-claimed-details-or-default token-id))
			(claim-details (try! (get-claim-details-or-fail token-id)))
			(alex-to-return (min (get available claim-details) (- (* (get stx-claimed claimed-details) multiplier) (get alex-returned claimed-details))))
			(updated-claimed (merge claimed-details { alex-returned: (+ (get alex-returned claimed-details) alex-to-return) })))
		(asserts! (not (is-paused)) err-paused)
		(asserts! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 is-paused) err-treasury-grant-v2-not-paused)
		(asserts! (is-eq (some sender) (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 get-owner token-id))) err-not-authorized)

		(map-set claimed token-id updated-claimed)		
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 pause false))
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 claim-alex token-id))
		(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.treasury-grant-v2 pause true))
		(and (> alex-to-return u0) (try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-alex transfer-fixed alex-to-return sender (as-contract tx-sender) none)))

		(print { notification: "claim-alex", payload: { token-id: token-id, owner: sender, claimed: (get available claim-details), returned: alex-to-return } })
		(ok true)))				

(define-public (claim-stx (token-id uint))
	(begin
		(try! (claim-stx-v2 token-id))
		(claim-stx-v3 token-id)))

(define-public (claim (token-id uint))
	(begin 
		(try! (claim-stx token-id))
		(claim-alex token-id)))

(define-public (claim-many (token-ids (list 1000 uint)))
  (ok (map claim token-ids)))

;; private calls

(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))

Functions (20)

FunctionAccessArgs
is-dao-or-extensionread-only
get-claim-baseread-only
get-claimed-details-or-defaultread-onlytoken-id: uint
get-claim-details-or-failread-onlytoken-id: uint
is-pausedread-only
add-to-claim-basepublicamount: uint
transfer-tokenpublictoken-trait: <ft-trait>, amount: uint, recipient: principal
pausepublicnew-paused: bool
callbackpublicsender: principal, payload: (buff 2048
executepublicsender: principal
claim-stx-v2publictoken-id: uint
claim-stx-v3publictoken-id: uint
claim-alexpublictoken-id: uint
claim-stxpublictoken-id: uint
claimpublictoken-id: uint
claim-manypublictoken-ids: (list 1000 uint
mul-downprivatea: uint, b: uint
div-downprivatea: uint, b: uint
minprivatea: uint, b: uint
maxprivatea: uint, b: uint