Source Code

;; Title: BME006 Treasury
;; Synopsis:
;; A treasury that can manage STX, SIP009, SIP010, and SIP013 tokens.
;; Description:
;; An extension contract that is meant to hold tokens on behalf of the
;; DAO. It can hold and transfer STX, SIP009, SIP010, and SIP013 tokens.
;; They can be deposited by simply transferring them to the contract.
;; Any extension or executing proposal can trigger transfers.
;; Technically, the ExecutorDAO core can hold and transfer tokens
;; directly. The treasury extension merely adds a bit of separation.

(impl-trait 'SP3JP0N1ZXGASRJ0F7QAHWFPGTVK9T2XNXDB908Z.extension-trait.extension-trait)
(use-trait prediction-market-trait 'SP3HAHEV768GAMP34MTEC83PJ4PG6ZSGBX52CR6XQ.prediction-market-trait.prediction-market-trait)
(use-trait ft-velar-token 'SP2AKWJYC7BNY18W1XXKPGP0YVEK63QJG4793Z2D4.sip-010-trait-ft-standard.sip-010-trait)

(define-constant err-unauthorised (err u3000))
(define-constant err-invalid-amount (err u3001))
(define-constant err-invalid-slippage (err u3002))

(define-constant share-fee-to 'SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.univ2-share-fee-to) 
(define-constant SCALE u1000000)

;; --- Transferable traits
(define-data-var slippage-bips uint u500) ;; default 5%

(define-trait sip009-transferable
	(
		(transfer (uint principal principal) (response bool uint))
	)
)

(define-trait sip010-transferable
	(
		(transfer (uint principal principal (optional (buff 34))) (response bool uint))
	)
)

(define-trait sip013-transferable
	(
		(transfer (uint uint principal principal) (response bool uint))
		(transfer-memo (uint uint principal principal (buff 34)) (response bool uint))
	)
)

(define-trait sip013-transferable-many
	(
		(transfer-many ((list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal})) (response bool uint))
		(transfer-many-memo ((list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal, memo: (buff 34)})) (response bool uint))
	)
)

;; --- Authorisation check

(define-public (is-dao-or-extension)
	(ok (asserts! (or (is-eq tx-sender .bigmarket-dao) (contract-call? .bigmarket-dao is-extension contract-caller)) err-unauthorised))
)

;; --- Internal DAO functions

(define-public (set-slippage-bips (bips uint))
  (begin
    (try! (is-dao-or-extension))
    (asserts! (and (>= bips u1) (<= bips u3000)) err-invalid-amount) ;; 0.01%..30% bounds
    (var-set slippage-bips bips)
    (ok true)
  )
)

(define-public (swap-tokens
  (token0 <ft-velar-token>) (token1 <ft-velar-token>)
  (token-in <ft-velar-token>) (token-out <ft-velar-token>)
  (amount uint)
)
  (let ((bips (var-get slippage-bips))
		(min-amount-scaled (/ (* (* amount (- u10000 bips)) SCALE) u10000))
		(min-amount (/ min-amount-scaled SCALE))
	)
    (try! (is-dao-or-extension))
    (asserts! (>= amount min-amount) err-invalid-amount)
    (try! (as-contract (contract-call? 'SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.univ2-router swap-exact-tokens-for-tokens
           u0 token0 token1 token-in token-out share-fee-to amount min-amount)))
    (print {event:"swap-tokens", amount:amount, min-amount:min-amount})
    (ok true)
  )
)

;;entrypoint to pass slippage per trade
(define-public (swap-tokens-with-slippage
  (token0 <ft-velar-token>) (token1 <ft-velar-token>)
  (token-in <ft-velar-token>) (token-out <ft-velar-token>)
  (amount uint) (slip-bips uint)
)
  (let (
		(min-amount-scaaled (/ (* (* amount (- u10000 slip-bips)) SCALE) u10000))
		(min-amount (/ min-amount-scaaled SCALE))
	)
    (try! (is-dao-or-extension))
    (asserts! (and (>= slip-bips u1) (<= slip-bips u3000)) err-invalid-slippage)
    (asserts! (> amount min-amount) err-invalid-amount)
    (try! (as-contract (contract-call? 'SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.univ2-router swap-exact-tokens-for-tokens
           u0 token0 token1 token-in token-out share-fee-to amount min-amount)))
    (print {event:"swap-tokens", amount:amount, min-amount:min-amount, slip-bips:slip-bips})
    (ok true)
  )
)


;; STX
(define-public (stx-transfer (amount uint) (recipient principal) (memo (optional (buff 34))))
	(begin
		(try! (is-dao-or-extension))
		(match memo to-print (print to-print) 0x)
		(as-contract (stx-transfer? amount tx-sender recipient))
	)
)

(define-public (stx-transfer-many (transfers (list 200 {amount: uint, recipient: principal, memo: (optional (buff 34))})))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (fold stx-transfer-many-iter transfers (ok true)))
	)
)

;; SIP009

(define-public (sip009-transfer (token-id uint) (recipient principal) (asset <sip009-transferable>))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (contract-call? asset transfer token-id tx-sender recipient))
	)
)

(define-public (sip009-transfer-many (data (list 200 {token-id: uint, recipient: principal})) (asset <sip009-transferable>))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (fold sip009-transfer-many-iter data asset))
		(ok true)
	)
)

;; SIP010

(define-public (sip010-transfer (amount uint) (recipient principal) (memo (optional (buff 34))) (asset <sip010-transferable>))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (contract-call? asset transfer amount tx-sender recipient memo))
	)
)

(define-public (sip010-transfer-many (data (list 200 {amount: uint, recipient: principal, memo: (optional (buff 34))})) (asset <sip010-transferable>))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (fold sip010-transfer-many-iter data asset))
		(ok true)
	)
)

;; SIP013

(define-public (sip013-transfer (token-id uint) (amount uint) (recipient principal) (memo (optional (buff 34))) (asset <sip013-transferable>))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (match memo memo-buff
			(contract-call? asset transfer-memo token-id amount tx-sender recipient memo-buff)
			(contract-call? asset transfer token-id amount tx-sender recipient)
		))
	)
)

(define-public (sip013-transfer-many (transfers (list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal})) (asset <sip013-transferable-many>))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (contract-call? asset transfer-many transfers))
	)
)

(define-public (sip013-transfer-many-memo (transfers (list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal, memo: (buff 34)})) (asset <sip013-transferable-many>))
	(begin
		(try! (is-dao-or-extension))
		(as-contract (contract-call? asset transfer-many-memo transfers))
	)
)

;; --- Iterator functions

(define-private (stx-transfer-many-iter (data {amount: uint, recipient: principal, memo: (optional (buff 34))}) (previous-result (response bool uint)))
	(begin
		(try! previous-result)
		(match (get memo data) to-print (print to-print) 0x)
		(stx-transfer? (get amount data) tx-sender (get recipient data))
	)
)

(define-private (sip009-transfer-many-iter (data {token-id: uint, recipient: principal}) (asset <sip009-transferable>))
	(begin
		(unwrap-panic (contract-call? asset transfer (get token-id data) tx-sender (get recipient data)))
		asset
	)
)

(define-private (sip010-transfer-many-iter (data {amount: uint, recipient: principal, memo: (optional (buff 34))}) (asset <sip010-transferable>))
	(begin
		(unwrap-panic (contract-call? asset transfer (get amount data) tx-sender (get recipient data) (get memo data)))
		asset
	)
)

;; --- Extension callback

(define-public (callback (sender principal) (memo (buff 34)))
	(ok true)
)

(define-public (claim-for-dao (market <prediction-market-trait>) (market-id uint) (token <ft-velar-token>))
  (begin
    (as-contract
      (contract-call? market claim-winnings market-id token)
    )
  )
)

Functions (15)

FunctionAccessArgs
is-dao-or-extensionpublic
set-slippage-bipspublicbips: uint
stx-transferpublicamount: uint, recipient: principal, memo: (optional (buff 34
stx-transfer-manypublictransfers: (list 200 {amount: uint, recipient: principal, memo: (optional (buff 34
sip009-transferpublictoken-id: uint, recipient: principal, asset: <sip009-transferable>
sip009-transfer-manypublicdata: (list 200 {token-id: uint, recipient: principal}
sip010-transferpublicamount: uint, recipient: principal, memo: (optional (buff 34
sip010-transfer-manypublicdata: (list 200 {amount: uint, recipient: principal, memo: (optional (buff 34
sip013-transferpublictoken-id: uint, amount: uint, recipient: principal, memo: (optional (buff 34
sip013-transfer-manypublictransfers: (list 200 {token-id: uint, amount: uint, sender: principal, recipient: principal}
stx-transfer-many-iterprivatedata: {amount: uint, recipient: principal, memo: (optional (buff 34
sip009-transfer-many-iterprivatedata: {token-id: uint, recipient: principal}, asset: <sip009-transferable>
sip010-transfer-many-iterprivatedata: {amount: uint, recipient: principal, memo: (optional (buff 34
callbackpublicsender: principal, memo: (buff 34
claim-for-daopublicmarket: <prediction-market-trait>, market-id: uint, token: <ft-velar-token>