Source Code

;; SPDX-License-Identifier: BUSL-1.1
;; treasury-grant-v4 - Contract for managing treasury grants and token distributions

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

;; Error codes for various failure scenarios
(define-constant ERR-NOT-AUTHORIZED (err u1000)) ;; When caller is not authorized
(define-constant ERR-TOKEN-MISMATCH (err u1001)) ;; When provided tokens don't match pool tokens
(define-constant ERR-ALREADY-CLAIMED (err u1002)) ;; When balance has already been claimed
(define-constant ERR-UPDATE-PRINCIPAL-MAP-FAILED (err u1003)) ;; When failed to update claim status
(define-constant ERR-INVALID-POOL-ID (err u1004)) ;; When provided pool ID is invalid

;; Constants for decimal handling and maximum values
(define-constant ONE_8 u100000000) ;; 1.0 with 8 decimal places
(define-constant MAX_UINT u340282366920938463463374607431768211455) ;; Maximum uint value

;; Snapshot block for balance calculations
;; __IF_MAINNET__				
(define-data-var snapshot-block uint u1509640)
;; (define-data-var snapshot-block uint u26356)
;; __ENDIF__

;; Exchange rates for different tokens (with 8 decimal places)
(define-data-var btc-rate uint u10273463917525) ;; 102,734.64 
(define-data-var stx-rate uint u67721865) ;; 0.67721865
(define-data-var usd-rate uint u100000000) ;; 1.00

;; Percentage of tokens to be lost/held (with 8 decimal places)
(define-data-var btc-pct uint u25000000) ;; 25%
(define-data-var stx-pct uint u100000000) ;; 100%
(define-data-var usd-pct uint u9000000) ;; 9%

;; Map to track which addresses have claimed their balances for specific pools
(define-map claimed { address: principal, pool-id: uint } bool)
(define-map claimed-expired { address: principal, pool-id: uint, cycle: uint } bool)
(define-map claimed-locked { address: principal, pool-id: uint } bool)

;; Check if caller is DAO or extension
(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)))

;; Getter functions for data variables
(define-read-only (get-snapshot-block)
	(var-get snapshot-block))

(define-read-only (get-btc-rate)
	(var-get btc-rate))

(define-read-only (get-stx-rate)
	(var-get stx-rate))

(define-read-only (get-usd-rate)
	(var-get usd-rate))

(define-read-only (get-btc-pct)
	(var-get btc-pct))

(define-read-only (get-stx-pct)
	(var-get stx-pct))

(define-read-only (get-usd-pct)
	(var-get usd-pct))

;; Setter functions for data variables (only callable by DAO or extension)
(define-public (set-snapshot-block (new-block uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set snapshot-block new-block))))

(define-public (set-btc-rate (new-rate uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set btc-rate new-rate))))

(define-public (set-stx-rate (new-rate uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set stx-rate new-rate))))

(define-public (set-usd-rate (new-rate uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set usd-rate new-rate))))

(define-public (set-btc-pct (new-pct uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set btc-pct new-pct))))

(define-public (set-stx-pct (new-pct uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set stx-pct new-pct))))

(define-public (set-usd-pct (new-pct uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set usd-pct new-pct))))

;; Get the balance of a specific pool for an address at the snapshot block
(define-read-only (get-pool-balance (pool-id uint) (address principal))
	(let (
			(snapshot-block-id (unwrap-panic (get-stacks-block-info? id-header-hash (var-get snapshot-block))))
			(snapshot-data (at-block snapshot-block-id
				(let (
						(pool-tokens (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-registry-v2-01 get-pool-details-by-id pool-id)))
						(pool-details (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01 get-pool-details (get token-x pool-tokens) (get token-y pool-tokens) (get factor pool-tokens))))
						(total-supply (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 get-total-supply-fixed pool-id)))
						(user-farm-details (match (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.alex-farming get-user-id 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 pool-id address)
							some-value (let ((reward-cycle (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.alex-farming get-reward-cycle 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 pool-id tenure-height))))
								(contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.alex-farming get-staker-at-cycle-or-default 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 pool-id reward-cycle some-value))
							{ amount-staked: u0, to-return: u0 }))
						(user-lp-balance (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 get-balance-fixed pool-id address)))
						(user-surge-balance-1 (contract-call? 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.farming-campaign-v2-01 get-campaign-staker-or-default u1 pool-id address))
						(user-surge-balance-2 (contract-call? 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.farming-campaign-v2-02 get-campaign-staker-or-default u2 pool-id address))
						(user-surge-balance-3 (contract-call? 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.farming-campaign-v2-03 get-campaign-staker-or-default u3 pool-id address))
						(user-surge-balance-4 (contract-call? 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.farming-campaign-v2-03 get-campaign-staker-or-default u4 pool-id address))
						(total-lp-balance (+ user-lp-balance (get amount-staked user-farm-details) (get to-return user-farm-details) (if (get claimed user-surge-balance-1) u0 (get amount user-surge-balance-1)) (if (get claimed user-surge-balance-2) u0 (get amount user-surge-balance-2)) (if (get claimed user-surge-balance-3) u0 (get amount user-surge-balance-3)) (if (get claimed user-surge-balance-4) u0 (get amount user-surge-balance-4)))))
					{ total-lp-balance: total-lp-balance, total-supply: total-supply, balance-x: (get balance-x pool-details), balance-y: (get balance-y pool-details), token-x: (get token-x pool-tokens), token-y: (get token-y pool-tokens) })))
		  (distribution-data (calculate-distribution pool-id (get total-lp-balance snapshot-data) (get total-supply snapshot-data) (get balance-x snapshot-data) (get balance-y snapshot-data) (get token-x snapshot-data) (get token-y snapshot-data))))
		distribution-data))

;; Helper function to iterate through pool balances
(define-private (get-pool-balance-iter (pool-id uint) (prior { address: principal, balances: (list 200 { pool-id: uint, total-lp-balance: uint, token-x-bal: uint, token-y-bal: uint, native-x-bal: uint, native-y-bal: uint, usdc-x-bal: uint, usdc-y-bal: uint, usdc-total-bal: uint }) }))
	(let (
			(pool-balance (get-pool-balance pool-id (get address prior)))
			(updated-balances (unwrap-panic (as-max-len? (append (get balances prior) pool-balance) u200))))
		{ address: (get address prior), balances: updated-balances }))

;; Get balances for multiple pools for an address
(define-read-only (get-pool-balance-many (address principal) (pool-ids (list 200 uint)))
	(fold get-pool-balance-iter pool-ids { address: address, balances: (list) }))

(define-read-only (get-locked-balance (pool-id uint) (address principal))
	(let (
			(snapshot-block-id (unwrap-panic (get-stacks-block-info? id-header-hash (var-get snapshot-block))))
			(snapshot-data (at-block snapshot-block-id
				(let (
						(pool-tokens (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-registry-v2-01 get-pool-details-by-id pool-id)))
						(pool-details (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01 get-pool-details (get token-x pool-tokens) (get token-y pool-tokens) (get factor pool-tokens))))
						(total-supply (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 get-total-supply-fixed pool-id)))					
						(locked-balance (contract-call? 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.liquidity-locker get-locked-liquidity-or-default address pool-id)))
					{ total-lp-balance: (get amount locked-balance), total-supply: total-supply, balance-x: (get balance-x pool-details), balance-y: (get balance-y pool-details), token-x: (get token-x pool-tokens), token-y: (get token-y pool-tokens) })))
		  (distribution-data (merge { memo: "locked" } (calculate-distribution pool-id (get total-lp-balance snapshot-data) (get total-supply snapshot-data) (get balance-x snapshot-data) (get balance-y snapshot-data) (get token-x snapshot-data) (get token-y snapshot-data)))))
		distribution-data))		

(define-read-only (get-expired-balance (pool-id uint) (address principal) (target-cycle uint))
	(let (
			(snapshot-block-id (unwrap-panic (get-stacks-block-info? id-header-hash (var-get snapshot-block))))
			(snapshot-data (at-block snapshot-block-id
				(let (
						(pool-tokens (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-registry-v2-01 get-pool-details-by-id pool-id)))
						(pool-details (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-pool-v2-01 get-pool-details (get token-x pool-tokens) (get token-y pool-tokens) (get factor pool-tokens))))
						(total-supply (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 get-total-supply-fixed pool-id)))
						(snapshot-cycle (unwrap-panic (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.alex-farming get-reward-cycle 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 pool-id tenure-height)))
						(user-farm-details 
							(match (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.alex-farming get-user-id 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 pool-id address)
								some-value
								(if (< target-cycle snapshot-cycle)
									(contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.alex-farming get-staker-at-cycle-or-default 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-amm-pool-v2-01 pool-id target-cycle some-value)
									{ amount-staked: u0, to-return: u0 })
								{ amount-staked: u0, to-return: u0 })))
					{ total-lp-balance: (get to-return user-farm-details), total-supply: total-supply, balance-x: (get balance-x pool-details), balance-y: (get balance-y pool-details), token-x: (get token-x pool-tokens), token-y: (get token-y pool-tokens) })))
		  (distribution-data (merge { cycle: target-cycle } (calculate-distribution pool-id (get total-lp-balance snapshot-data) (get total-supply snapshot-data) (get balance-x snapshot-data) (get balance-y snapshot-data) (get token-x snapshot-data) (get token-y snapshot-data)))))
		distribution-data))			

(define-private (get-expired-balance-iter (pool-cycle { pool-id: uint, cycle: uint }) (prior { address: principal, balances: (list 200 { pool-id: uint, cycle: uint, total-lp-balance: uint, token-x-bal: uint, token-y-bal: uint, native-x-bal: uint, native-y-bal: uint, usdc-x-bal: uint, usdc-y-bal: uint, usdc-total-bal: uint }) }))
	(let (
			(expired-balance (get-expired-balance (get pool-id pool-cycle) (get address prior) (get cycle pool-cycle)))
			(updated-balances (unwrap-panic (as-max-len? (append (get balances prior) expired-balance) u200))))
		{ address: (get address prior), balances: updated-balances }))

;; Get balances for multiple pools for an address
(define-read-only (get-expired-balance-many (address principal) (pool-cycles (list 200 { pool-id: uint, cycle: uint })))
	(fold get-expired-balance-iter pool-cycles { address: address, balances: (list) }))

;; Check if a balance has been claimed
(define-read-only (get-claimed-or-default (address principal) (pool-id uint))
	(or
		(contract-call? .treasury-grant-v4-1 get-claimed-or-default address pool-id)
		(contract-call? .treasury-grant-v4-2 get-claimed-or-default address pool-id)
		(contract-call? .treasury-grant-v4-3 get-claimed-or-default address pool-id)
	(default-to false (map-get? claimed { address: address, pool-id: pool-id }))))

(define-read-only (get-claimed-locked-or-default (address principal) (pool-id uint))
	(default-to false (map-get? claimed-locked { address: address, pool-id: pool-id })))

(define-read-only (get-claimed-expired-or-default (address principal) (pool-id uint) (cycle uint))
	(default-to false (map-get? claimed-expired { address: address, pool-id: pool-id, cycle: cycle })))

(define-public (claim-balance (details { dest: (buff 256), pool-id: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> }))
	(let (
			(pool-id (get pool-id details))
			(pool-tokens (try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-registry-v2-01 get-pool-details-by-id pool-id)))
			(pool-balance (get-pool-balance pool-id tx-sender))
			(locked-balance (get-locked-balance pool-id tx-sender))
			(token-x-trait (get token-x-trait details))
			(token-y-trait (get token-y-trait details))
			(check-token-x (asserts! (is-eq (get token-x pool-tokens) (contract-of token-x-trait)) ERR-TOKEN-MISMATCH))		
			(check-token-y (asserts! (is-eq (get token-y pool-tokens) (contract-of token-y-trait)) ERR-TOKEN-MISMATCH))
			(check-pool-id (asserts! (not (is-eq pool-id u170)) ERR-INVALID-POOL-ID))
			(claimed-pool-balance (if (get-claimed-or-default tx-sender pool-id) 
				false 
				(begin
					(try! (send-native-balances (get native-x-bal pool-balance) (get native-y-bal pool-balance) token-x-trait token-y-trait))
					(asserts! (map-set claimed { address: tx-sender, pool-id: pool-id } true) ERR-UPDATE-PRINCIPAL-MAP-FAILED)
					(print (merge pool-balance { address: tx-sender, dest: (get dest details), claimed: true }))
					true)))
			(claimed-locked-balance (if (get-claimed-locked-or-default tx-sender pool-id) 
				false 
				(begin
					(try! (send-native-balances (get native-x-bal locked-balance) (get native-y-bal locked-balance) token-x-trait token-y-trait))
					(asserts! (map-set claimed-locked { address: tx-sender, pool-id: pool-id } true) ERR-UPDATE-PRINCIPAL-MAP-FAILED)
					(print (merge locked-balance { address: tx-sender, dest: (get dest details), claimed: true }))
					true))))
		(ok { pool-id: pool-id, claim-pool-balance: claimed-pool-balance, claim-locked-balance: claimed-locked-balance })))

(define-private (claim-balance-iter (details { dest: (buff 256), pool-id: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> }) (prior (response (list 200 { pool-id: uint, claim-pool-balance: bool, claim-locked-balance: bool }) uint)))
	(match prior 
		ok-value 
		(ok (unwrap-panic (as-max-len? (append ok-value (try! (claim-balance details))) u200)))
		err-value prior))

(define-public (claim-balance-many (details (list 200 { dest: (buff 256), pool-id: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> })))
	(fold claim-balance-iter details (ok (list))))

(define-public (claim-expired-balance (details { dest: (buff 256), pool-id: uint, cycle: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> }))
	(let (
			(pool-id (get pool-id details))
			(cycle (get cycle details))
			(pool-tokens (try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-registry-v2-01 get-pool-details-by-id pool-id)))
			(expired-balance (get-expired-balance pool-id tx-sender cycle))
			(token-x-trait (get token-x-trait details))
			(token-y-trait (get token-y-trait details))
			(check-token-x (asserts! (is-eq (get token-x pool-tokens) (contract-of token-x-trait)) ERR-TOKEN-MISMATCH))
			(check-token-y (asserts! (is-eq (get token-y pool-tokens) (contract-of token-y-trait)) ERR-TOKEN-MISMATCH))
			(check-pool-id (asserts! (not (is-eq pool-id u170)) ERR-INVALID-POOL-ID))
			(claimed-expired-balance (if (get-claimed-expired-or-default tx-sender pool-id cycle)
				false 
				(begin
					(try! (send-native-balances (get native-x-bal expired-balance) (get native-y-bal expired-balance) token-x-trait token-y-trait))
					(asserts! (map-set claimed-expired { address: tx-sender, pool-id: pool-id, cycle: cycle } true) ERR-UPDATE-PRINCIPAL-MAP-FAILED)
					(print (merge expired-balance { address: tx-sender, dest: (get dest details), claimed: true }))
					true))))
		(ok { pool-id: pool-id, claim-expired-balance: claimed-expired-balance })))

(define-private (claim-expired-balance-iter (details { dest: (buff 256), pool-id: uint, cycle: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> }) (prior (response (list 200 { pool-id: uint, claim-expired-balance: bool }) uint)))
	(match prior 
		ok-value 
		(ok (unwrap-panic (as-max-len? (append ok-value (try! (claim-expired-balance details))) u200)))
		err-value prior))

;; Claim balances from multiple pools
(define-public (claim-expired-balance-many (details (list 200 { dest: (buff 256), pool-id: uint, cycle: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> })))
	(fold claim-expired-balance-iter details (ok (list))))

(define-public (claim-all-balance-many 
	(details (list 200 { dest: (buff 256), pool-id: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> }))
	(expired-details (list 200 { dest: (buff 256), pool-id: uint, cycle: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait> })))
	(begin
		(print (try! (claim-balance-many details)))
		(print (try! (claim-expired-balance-many expired-details)))
		(ok true)))

(define-private (send-native-balances (native-x-bal uint) (native-y-bal uint) (token-x-trait <ft-trait>) (token-y-trait <ft-trait>))
	(begin		
		(and
			(> native-x-bal u0)
			(if (is-eq (contract-of token-x-trait) 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.token-wsbtc)
				(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-vault-v2-01 transfer-ft 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-abtc native-x-bal tx-sender))
				(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-vault-v2-01 transfer-ft token-x-trait native-x-bal tx-sender))))		
		(and
			(> native-y-bal u0)
			(if (is-eq (contract-of token-y-trait) 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.token-wsbtc)
				(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-vault-v2-01 transfer-ft 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-abtc native-y-bal tx-sender))
				(try! (contract-call? 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.amm-vault-v2-01 transfer-ft token-y-trait native-y-bal tx-sender))))
	(ok true)))

(define-private (calculate-distribution (pool-id uint) (total-lp-balance uint) (total-supply uint) (balance-x uint) (balance-y uint) (token-x principal) (token-y principal))
	(let (
		(token-x-bal (if (is-eq total-supply u0) u0 (/ (* (/ (* total-lp-balance ONE_8) total-supply) balance-x) ONE_8)))
		(token-y-bal (if (is-eq total-supply u0) u0 (/ (* (/ (* total-lp-balance ONE_8) total-supply) balance-y) ONE_8)))
		(lost-x-bal (if (or (is-eq token-x 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-abtc) (is-eq token-x 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.token-wsbtc)) (mul-down token-x-bal (var-get btc-pct)) (if (is-eq token-x 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2) (mul-down token-x-bal (var-get stx-pct)) (if (is-eq token-x 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-susdt) (mul-down token-x-bal (var-get usd-pct)) u0))))
		(lost-y-bal (if (or (is-eq token-y 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-abtc) (is-eq token-y 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.token-wsbtc)) (mul-down token-y-bal (var-get btc-pct)) (if (is-eq token-y 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2) (mul-down token-y-bal (var-get stx-pct)) (if (is-eq token-y 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-susdt) (mul-down token-y-bal (var-get usd-pct)) u0))))
		(native-x-bal (- token-x-bal lost-x-bal))
		(native-y-bal (- token-y-bal lost-y-bal))
		(usdc-x-bal (if (or (is-eq token-x 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-abtc) (is-eq token-x 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.token-wsbtc)) (mul-down lost-x-bal (var-get btc-rate)) (if (is-eq token-x 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2) (mul-down lost-x-bal (var-get stx-rate)) (if (is-eq token-x 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-susdt) (mul-down lost-x-bal (var-get usd-rate)) u0))))
		(usdc-y-bal (if (or (is-eq token-y 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-abtc) (is-eq token-y 'SP1E0XBN9T4B10E9QMR7XMFJPMA19D77WY3KP2QKC.token-wsbtc)) (mul-down lost-y-bal (var-get btc-rate)) (if (is-eq token-y 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM.token-wstx-v2) (mul-down lost-y-bal (var-get stx-rate)) (if (is-eq token-y 'SP2XD7417HGPRTREMKF748VNEQPDRR0RMANB7X1NK.token-susdt) (mul-down lost-y-bal (var-get usd-rate)) u0)))))
	{ pool-id: pool-id, total-lp-balance: total-lp-balance, token-x-bal: token-x-bal, token-y-bal: token-y-bal, native-x-bal: native-x-bal, native-y-bal: native-y-bal, usdc-x-bal: usdc-x-bal, usdc-y-bal: usdc-y-bal, usdc-total-bal: (+ usdc-x-bal usdc-y-bal) }))


;; Multiply two numbers and divide by ONE_8 to handle decimals
(define-private (mul-down (a uint) (b uint))
	(/ (* a b) ONE_8))

;; Divide two numbers with proper decimal handling
(define-private (div-down (a uint) (b uint))
	(if (is-eq a u0) u0 (/ (* a ONE_8) b)))

;; Get minimum of two numbers
(define-private (min (a uint) (b uint))
	(if (<= a b) a b))

;; Get maximum of two numbers
(define-private (max (a uint) (b uint))
	(if (>= a b) a b))

Functions (29)

FunctionAccessArgs
is-dao-or-extensionread-only
get-snapshot-blockread-only
get-btc-rateread-only
get-stx-rateread-only
get-usd-rateread-only
get-btc-pctread-only
get-stx-pctread-only
get-usd-pctread-only
set-snapshot-blockpublicnew-block: uint
set-btc-ratepublicnew-rate: uint
set-stx-ratepublicnew-rate: uint
set-usd-ratepublicnew-rate: uint
set-btc-pctpublicnew-pct: uint
set-stx-pctpublicnew-pct: uint
set-usd-pctpublicnew-pct: uint
get-pool-balanceread-onlypool-id: uint, address: principal
get-pool-balance-manyread-onlyaddress: principal, pool-ids: (list 200 uint
get-locked-balanceread-onlypool-id: uint, address: principal
get-expired-balanceread-onlypool-id: uint, address: principal, target-cycle: uint
get-expired-balance-manyread-onlyaddress: principal, pool-cycles: (list 200 { pool-id: uint, cycle: uint }
get-claimed-or-defaultread-onlyaddress: principal, pool-id: uint
get-claimed-locked-or-defaultread-onlyaddress: principal, pool-id: uint
get-claimed-expired-or-defaultread-onlyaddress: principal, pool-id: uint, cycle: uint
send-native-balancesprivatenative-x-bal: uint, native-y-bal: uint, token-x-trait: <ft-trait>, token-y-trait: <ft-trait>
calculate-distributionprivatepool-id: uint, total-lp-balance: uint, total-supply: uint, balance-x: uint, balance-y: uint, token-x: principal, token-y: principal
mul-downprivatea: uint, b: uint
div-downprivatea: uint, b: uint
minprivatea: uint, b: uint
maxprivatea: uint, b: uint